4804: 欧拉心算
Time Limit: 15 Sec Memory Limit: 256 MB
Submit: 229 Solved: 147
[Submit][Status][Discuss]
Description
给出一个数字N
Input
第一行为一个正整数T,表示数据组数。
接下来T行为询问,每行包含一个正整数N。
T<=5000,N<=10^7
Output
按读入顺序输出答案。
Sample Input
1
10
Sample Output
136
HINT
Source
By FancyCoder
[Submit][Status][Discuss]
大力莫比乌斯反演可以得到
Ans=∑ni=1∑nj=1ϕ(gcd(i,j))=∑ni=1ϕ(i)∑⌊ni⌋d=1μ(d)⌊nid⌋2
记 g(n)=∑nd=1μ(d)⌊nd⌋2
注意到 ⌊nd⌋−⌊n−1d⌋=1 成立当且仅当 d|n
那么 g(n)=g(n−1)+∑d|nμ(d)(2nd−1)
由于 ∑d|nμ(d)d=ϕ(n)n
g(n)=g(n−1)+2ϕ(d)−[n=1]
于是 Ans=∑ni=1ϕ(i)g(⌊ni⌋)
复杂度 O(TN−−√)
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define min(a,b) ((a) < (b) ? (a) : (b))
using namespace std;
const int maxn = 5005;
const int N = 10000007;
typedef long long LL;
int T,n,tot,pri[N],Q[maxn];
LL phi[N],g[N];
bool not_pri[N];
void Solve(int n)
{
LL Ans = 0;
for (int i = 1,last; i <= n; i = last + 1)
{
int tmp = n / i; last = n / tmp;
Ans += (phi[last] - phi[i - 1]) * g[tmp];
}
printf("%lld\n",Ans);
}
int main()
{
#ifdef DMC
freopen("DMC.txt","r",stdin);
#endif
cin >> T; phi[1] = g[1] = 1;
for (int i = 1; i <= T; i++)
scanf("%d",&Q[i]),n = max(n,Q[i]);
for (int i = 2; i <= n; i++)
{
if (!not_pri[i])
pri[++tot] = i,phi[i] = i - 1;
for (int j = 1; j <= tot; j++)
{
int Nex = i * pri[j];
if (Nex > n) break;
not_pri[Nex] = 1;
if (i % pri[j] == 0)
{
phi[Nex] = phi[i] * pri[j]; break;
}
phi[Nex] = phi[i] * (pri[j] - 1);
}
g[i] = g[i - 1] + 2LL * phi[i];
}
for (int i = 2; i <= n; i++) phi[i] += phi[i - 1];
for (int i = 1; i <= T; i++) Solve(Q[i]);
return 0;
}