本来找了O(n^1/2)的方法,对拍过后没问题,交上竟然超时,果然复杂度需要更低,然而这就属于不在我的能力范围之内的积性函数的运用了
但是,发现只要这个知识点我学过,那么只要时间足够,就一定能想出做法,在做这个题时想过放弃,但是坚持就会有好的结果
根n算法
通过打表,找了一下规律,同时发现gcd(a,n)==gcd(b,n)==d,那么,他们最大公约数相同,化成lcm就是a*n/d,b*nd,发现是可以合并的式子
也就是说只要找到所有的因子,并在O(1)的时间求出所要gcd==d数的总和就可以算出来
36的表
36
36 1 1 36//可以发现第一个数+最后一个数==n,且中间也是如此,所以只需求出gcd==d的个数然后代公式即可
36 5 1 180//当然是通过phi【n/i】来求个数喽~
36 7 1 252
36 11 1 396
36 13 1 468
36 17 1 612
36 19 1 684
36 23 1 828
36 25 1 900
36 29 1 1044
36 31 1 1116
36 35 1 1260
36 2 2 36
36 10 2 180
36 14 2 252
36 22 2 396
36 26 2 468
36 34 2 612
36 3 3 36
36 15 3 180
36 21 3 252
36 33 3 396
36 4 4 36
36 8 4 72
36 16 4 144
36 20 4 180
36 28 4 252
36 32 4 288
36 6 6 36
36 30 6 180
36 9 9 36
36 27 9 108
36 12 12 36
36 24 12 72
36 18 18 36
36 36 36 36
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
int pri[1000009],phi[1000009];
bool b[1000009];
int main()
{
int T;
phi[1]=1;
int N=1000000;
for (int i=2;i<=N;i++)
{
if (!b[i])
{
phi[i]=i-1;
pri[++pri[0]]=i;
}
for (int j=1;j<=pri[0]&&i*pri[j]<=N;j++)
{
b[pri[j]*i]=true;
if (i%pri[j]==0)
{
phi[i*pri[j]]=phi[i]*pri[j];
break;
}else phi[i*pri[j]]=phi[i]*(pri[j]-1);
}
}///get phi
//for (int i=1;i<=100;i++) printf("%d ",phi[i]);
scanf("%d",&T);
while (T--)
{
long long n;
scanf("%lld",&n);
long long ans=0;
int sq=(long long)sqrt(n);
for (int i=1;i<=sq;i++) if (n%i==0)
{
int k=i;
ans+=n/i*n*phi[n/i]/2;
k=n/i;
if (k==i) continue;//不要重复计算,把因数遍历,6*6=36,只有一种
if (k!=n) ans+=n/k*n*phi[n/k]/2;else ans+=n;//注意特殊情况的处理
}
if (n==1) ans=1;
printf("%lld\n",ans);
}
return 0;
}
打表代码
#include<cstdio>
#include<algorithm>
using namespace std;
int n;
struct aa
{
int gcd,a,b;
bool operator <(const aa bb)const
{
if (gcd!=bb.gcd)return gcd<bb.gcd;
else return b<bb.b;
}
}x[1009];
int gcd(int a,int b)
{
return b? gcd(b,a%b):a;
}
int main()
{
while (scanf("%d",&n)!=EOF)
{
int k=0;
for (int i=1;i<=n;i++) x[i].gcd=gcd(n,i),x[i].b=i;
sort(x+1,x+n+1);
for (int i=1;i<=n;i++) printf("%d %d %d %d\n",n,x[i].b,x[i].gcd,n*x[i].b/x[i].gcd);
}
return 0;
}
学一下标准做法
Problem Three:[SPOJ LCMSUM]sigma(lcm(i, n)),1 ≤ i ≤ n. 多组询问
令S(i)= Sigma(i,i|n) =>iphi(i)/2
则Ans=nSigma(S(d),d|n)
直接做预处理phi(i),然后枚举约数,复杂度:O(N)-O(sqrt(N)).
令G(i)=iphi(i)/2,i|n,不难发现Ans=N((G(N)-1)/2+1).
由于可证G(N)是积性函数,所以我们可以在O(N)的时间内算出G(N),询问O(1).