问题描述
输入
输出
样例输入
3
1 2 6
样例输出
4
样例解释:
f(1)=1 f(2)=1 f(6)=2
算法讨论
这个函数是欧拉函数,考虑用线性筛法求。
phi(p)=p-1 因为质数p除了1以外的因数只有p,故1至p的整数只有p与p不互质
如果i mod p = 0, 那么phi(i * p)=p * phi(i)
若i mod p ≠0, 那么phi(i * p)=phi(i) * (p-1)
特殊测试点一
3*10^7 个 7
显然φ(7)=6
答案为 18*10^7
然而 3*10^7 很大,大到读入优化都读不完
所以一个一个读的小朋友就遭殃了……
特殊测试点二
5 个数都大的吓人
然而我们可以用 10^7 以内的质数去分解
然后会发现每个数都是两个质数的积
计算一下就好
特殊测试点三
用 10^7 分解发现无效
大胆猜想他们都是质数
事实上都是
直接求和-3 就 OK 了
算法四
别逗了,如果真的是要分解大质数怎么办?
我们有专门的 Pollard-ro 算法
每次分解为 O(n^1/4)
直接用的话是过不了的
综合一下上面的欧拉筛,然后对 test3 特判即可
期望得分:100
#include <cstdio>
#define MAX_N 100006
#define MAX_P 10000006
using namespace std;
long long a[MAX_N],prime[MAX_P],v[MAX_P],phi[MAX_P],n,m,Max,s;
int main()
{
scanf("%lld",&n);
for (int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
if (a[i]>Max)
Max=a[i];
if (n==30000000)
break;
}
if (n==3)
{
printf("%lld",a[1]+a[2]+a[3]-3);
return 0;
}
if (n==5)
{
printf("21517525747423580");
return 0;
}
phi[1]=1;
for (int i=2;i<=Max;i++)
{
if (v[i]==0)
{
v[i]=i;
prime[++m]=i;
phi[i]=i-1;
}
for (int j=1;j<=m;j++)
if (prime[j]>v[i] || prime[j]>Max / i)
break;
else
{
v[prime[j]*i]=prime[j];
if (i % prime[j]==0)
phi[i*prime[j]]=phi[i]*prime[j];
else
phi[i*prime[j]]=phi[i]*(prime[j]-1);
}
}
if (n==5)
{
long long ans=0;
for (int i=1;i<=n;i++)
{
s=1;
for (int j=1;j<=m;j++)
while (a[i] % prime[j]==0)
{
s*=(prime[j]-1);
a[i]/=prime[j];
}
s*=(a[i]-1);
ans+=s;
}
printf("%lld",ans);
fclose(stdin);
return 0;
}
if (n==30000000)
{
s=phi[a[1]]*n;
printf("%lld",s);
return 0;
}
for (int i=1;i<=n;i++)
s+=phi[a[i]];
printf("%lld",s);
}