Description
Input
一共T+1行
第1行为数据组数T(T<=10)
第2~T+1行每行一个非负整数N,代表一组询问
Output
一共T行,每行两个用空格分隔的数ans1,ans2
Sample Input
6
1
2
8
13
30
2333
Sample Output
1 1
2 0
22 -2
58 -3
278 -3
1655470 2
分析:杜教筛模版题。
代码:
#include <iostream>
#include <cstdio>
#include <cmath>
#include <map>
#define LL long long
const int maxn=5e6+7;
using namespace std;
LL test,n,cnt;
LL phi[maxn],mul[maxn],g[maxn];
LL f[maxn];
LL prime[maxn],not_prime[maxn];
map <LL,LL> a,b;
void getf(LL n)
{
phi[1]=1;
mul[1]=1;
for (LL i=2;i<=n;i++)
{
if (!not_prime[i])
{
prime[++cnt]=i;
phi[i]=i-1;
mul[i]=-1;
}
for (LL j=1;j<=cnt;j++)
{
if (i*prime[j]>n) break;
not_prime[i*prime[j]]=1;
if (i%prime[j]==0)
{
phi[i*prime[j]]=phi[i]*prime[j];
mul[i*prime[j]]=0;
break;
}
else
{
phi[i*prime[j]]=phi[i]*(prime[j]-1);
mul[i*prime[j]]=-mul[i];
}
}
}
for (LL i=1;i<=n;i++)
{
f[i]=f[i-1]+phi[i];
g[i]=g[i-1]+mul[i];
}
}
LL sum_phi(LL n)
{
if (n<=5e6) return f[n];
LL c=a[n];
if (c) return c;
LL sum=0;
for (LL i=2,last;i<=n;i=last+1)
{
last=n/(n/i);
sum+=sum_phi(n/i)*(last-i+1);
}
c=n*(n+1)/2-sum;
a[n]=c;
return c;
}
LL sum_mul(LL n)
{
if (n<=5e6) return g[n];
LL c=b[n];
if (c) return c;
LL sum=0;
for (LL i=2,last;i<=n;i=last+1)
{
last=n/(n/i);
sum+=sum_mul(n/i)*(last-i+1);
}
c=1-sum;
b[n]=c;
return c;
}
int main()
{
scanf("%lld",&test);
getf(5e6);
while (test--)
{
scanf("%lld",&n);
printf("%lld %lld\n",sum_phi(n),sum_mul(n));
}
}