题目链接:哆啦A梦传送门
题解:
参考博客:http://acm.hdu.edu.cn/showproblem.php?pid=6434
我们令 a=i-j,那么由 j<=i-1,得 i-j>=1,再有 j>=1,的 i-j<=i-1。
由辗转相除法可得下式。
故题目就变成求 与i互质的数(小于i)有多少个?但题目是求2*i的,
所以当i为偶数时,与i互质的数一定是奇数,那么
当i为奇数时,与i互质的偶数有个,那么
,最后我们处理下前缀和就行了。
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long LL;
const int maxn=2e7+10;
int phi[maxn],pri[maxn],tot;
bool vis[maxn];
void init()
{
memset(vis,0,sizeof(vis));
tot=0;
int n=maxn-5;
phi[1]=1;
for(int i=2;i<=n;i++)
{
if(!vis[i]){
phi[i]=i-1;
pri[++tot]=i;
}
for(int j=1;j<=tot;j++)
{
int x=pri[j];
if(i*x>n) break;
vis[i*x]=1;
if(i%x==0){
phi[i*x]=phi[i]*x;break;
}
else{
phi[i*x]=phi[i]*phi[x];
}
}
}
}
LL sum[maxn];
int main()
{
init();
int n,ncase;
scanf("%d",&ncase);
sum[0]=sum[1]=0;
for(int i=2;i<=20000000;i++)
{
if(i%2==1) sum[i]=sum[i-1]+phi[i]/2;
else sum[i]=sum[i-1]+phi[i];
}
while(ncase--)
{
scanf("%d",&n);
printf("%lld\n",sum[n]);
}
return 0;
}