NKOJ3801 分解质因数
问题描述
记Pi表示正整数i的质因数集合。
已知正整数n,求满足下列条件的有序正整数对(a,b)的数目:
(1)1<=a<=b<=n
(2)t为a,b的最大公约数,Pt是Pn的子集
输入格式
一个正整数n.
输出格式
一个正整数,表示合题意的有序正整数对的数目.
样例输入 1
6
样例输出 1
20
样例输入 2
7
样例输出 2
19
数据范围
50%的数据1<=n<=2000;
100%的数据1<=n<=1000000.
来源 @lym01803
1是没有质因数的,因此1的质因数集合是空集,而空集属于所有集合。此时显然可以用欧拉函数来搞。
注意到欧拉函数的计算式:
ϕ(x)=x(1−1p1)(1−1p2)(1−1p3)…(1−1pk),p1,p2…pk,x=pa11pa22pa33…pakk
欧拉函数函数的本质是容斥原理。那么将欧拉函数稍加改动,设p是Pn中的元素,那么我们可以先求出正常的 ϕ(x) ,当 p|x 时将 ϕ(x) 乘上 pp−1 得到 ϕ′(x) ,即可消除容斥原理的影响。
这样的话,最终答案就是 ∑ni=1ϕ′(i)
#include<stdio.h>
#define ll long long
#define MAXN 1000005
int N,E[MAXN];
ll Ans,phi[MAXN],P[MAXN];
void Euler(int x)
{
int i,j;
phi[1]=1;
for(i=2;i<=x;i++)
{
if(!phi[i])phi[i]=i-1,P[++P[0]]=i;
for(j=1;j<=P[0]&&i*P[j]<=x;j++)
{
if(i%P[j]==0)
{
phi[i*P[j]]=phi[i]*P[j];
break;
}
else phi[i*P[j]]=phi[i]*phi[P[j]];
}
}
}
int main()
{
int i,j;
scanf("%d",&N);
Euler(N);
for(i=1;i<=P[0]&&P[i]<=N;i++)if(N%P[i]==0)E[++E[0]]=P[i];
for(i=1;i<=N;i++)
for(j=1;j<=E[0];j++)
{
if(i%E[j]==0)phi[i]=phi[i]*E[j]/(E[j]-1);
}
for(i=1;i<=N;i++)Ans+=phi[i];
printf("%lld",Ans);
}