题目大意:
计算:
G=∑i<Ni=1∑j<=Nj=i+1GCD(i,j)
难度系数(往下递增):
- UVA11426
- FZU1969
- 51NOD1188
题目思路一:
G=∑ng=1g(∑phi(⌊gd⌋−1)
求这么个东西,我们先预处理欧拉函数,然后枚举公约数g。
显然对于
⌊gd⌋
我们可以分块求。
时间复杂度:
O(T*sqrt(n))
题目思路二:
因为51NOD,其样例数过多,那么我们就要想一种更快的办法。现在我们需要枚举公约数g,计算一下他们对其的倍数的贡献。然后在nlogn的时间里预处理出res[i](答案数组)。
伪代码:
for(int g=1;g<maxn/2;g++)
for(int i=g+g;i<maxn;i+=g)
res[i]+=(LL)g*phi[i/g];
时间复杂度:
O(nlogn+T)
( Orz 恩,这个做法感觉合理多了呢? )
代码如下:
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn=5e6+5;
int phi[maxn],prime[maxn],primesize;
LL res[maxn];
bool isprime[maxn];
const int read()
{
char ch = getchar();
while (ch<'0' || ch>'9') ch = getchar();
int x = ch - '0';
while ((ch = getchar()) >= '0'&&ch <= '9') x = x * 10 + ch - '0';
return x;
}
template <class T>
inline void print_d(T x)
{
if (x > 9)
{
print_d(x / 10);
}
putchar(x % 10 + '0');
}
int main()
{
for(int i=2;i<maxn;i++)
{
if(!isprime[i])
{
prime[++primesize]=i;
phi[i]=i-1;
}
for(int j=1;j<=primesize&&i*prime[j]<maxn;j++)
{
isprime[i*prime[j]]=true;
if(i%prime[j]==0)
{
phi[i*prime[j]]=phi[i]*prime[j];
break;
}
phi[i*prime[j]]=phi[i]*(prime[j]-1);
}
}
for(int g=1;g<maxn/2;g++) for(int i=g+g;i<maxn;i+=g) res[i]+=(LL)g*phi[i/g];
res[0]=0;
for(int i=1;i<maxn;i++) res[i]+=res[i-1];
int n,T;
T=read();
while(T--)
{
n=read();
print_d(res[n]);
putchar('\n');
}
}