ff[i]:i的倍数的个数
gg[i]:gcd==i的集合的个数
kk[i]:和i不互质的数的个数
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int mod=1e9+7;
typedef __int64 LL;
int _pow(int a,int b){
int c=1;
while(b){
if(b&1){
c=(LL)c*a%mod;
}
a=(LL)a*a%mod;
b/=2;
}
return c;
}
const int N=1e7+10;
int ff[N],gg[N],kk[N],mu[N],pn,pri[N];
void init(){
memset(ff,0,sizeof(ff));
pn=0;
int n=1e7;
for(int i=2;i<=n;i++){
if(!ff[i]){
mu[i]=1;
pri[pn++]=i;
}
for(int j=0;j<pn;j++){
if(pri[j]>n/i)break;
ff[i*pri[j]]=1;
if(i%pri[j]==0){
mu[i*pri[j]]=0;
break;
}
else {
mu[i*pri[j]]=-mu[i];
}
}
}
}
void prin(int mx){
for(int i=2;i<=mx;i++){
printf("%d:%d %d %d\n",i,ff[i],gg[i],kk[i]);
}
}
int main(){
#ifdef DouBi
freopen("in.cpp","r",stdin);
//freopen("out.cpp","w",stdout);
#endif // DouBi
int n;
init();
// for(int i=2;i<=10;i++){
// printf("%d %d\n",i,mu[i]);
// }
while(scanf("%d",&n)!=EOF){
memset(ff,0,sizeof(ff));
memset(gg,0,sizeof(gg));
memset(kk,0,sizeof(kk));
int mx=2;
for(int i=0;i<n;i++){
int a;scanf("%d",&a);
mx=max(mx,a);
ff[a]++;
}
for(int i=2;i<=mx;i++){
for(int j=i*2;j<=mx;j+=i){
ff[i]+=ff[j];
}
}
for(int i=2;i<=mx;i++)if(mu[i]){
for(int j=i;j<=mx;j+=i){
kk[j]+=mu[i]*ff[i];
if(kk[j]>=mod)kk[j]-=mod;
if(kk[j]<0)kk[j]+=mod;
}
}
for(int i=mx;i>=2;i--){
gg[i]=_pow(2,ff[i])-1;
if(gg[i]<0)gg[i]+=mod;
for(int j=i*2;j<=mx;j+=i){
gg[i]-=gg[j];
if(gg[i]<0)gg[i]+=mod;
}
}
//prin(mx);
int ans=0;
for(int i=2;i<=mx;i++){
ans+=(LL)(n-kk[i])*gg[i]%mod;
if(ans>=mod)ans-=mod;
}
printf("%d\n",ans);
}
return 0;
}
本文介绍了一个涉及数论的算法实现,其中包括求解i的倍数个数、与i互质的数的个数以及特定条件下集合的数量。通过预处理得到欧拉函数值,并利用这些值进行进一步的计算。

1022

被折叠的 条评论
为什么被折叠?



