CF585E:Present for Vitalik the Philatelist
Posted Blue233333
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CF585E:Present for Vitalik the Philatelist相关的知识,希望对你有一定的参考价值。
n<=500000个2<=Ai<=1e7的数,求这样选数的方案数:先从其中挑出一个gcd不为1的集合,然后再选一个不属于该集合,且与该集合内任意一个数互质的数。
好的统计题。
其实就是要对每个数求和他互质的,gcd不为1的集合数,容斥一下,求出所有gcd不为1的集合数A然后减去所有他的质因子对这个A的贡献。(这里的A是CF的题解的B)
那先看看所有gcd不为1的集合数怎么求。比如说2的倍数有cnt_2个,那能凑出2^cnt_2-1个集合,然后3的倍数有cnt_3个,能凑出2^cnt_3-1个集合,但有一些gcd为6的集合被算了两次,就要减去2^cnt_6-1,等等这不是莫比乌斯函数嘛,所以现在只要统计1~1e7中每个数作为多少个数的因数即可。那要把n个数都进行分解,这里可以在筛莫比乌斯的时候记一下每个数的最小质因子就可以n*logMax的时间内完成所有数的分解。由于miu_i=0的cnt_i对答案没贡献,所以每个数分解完的质因子不用去考虑那些次数大于1的部分,比如12=2*2*3直接看2和3即可。把不重复质数分解出来后,在1e7内一个数最多有8个不同质因子,所以枚举一下所有这些质因子能凑出的数即可计算miu_i不为0的cnt_i。
然后某个数的质因子对A的贡献呢?同理耶!
1 #include<stdio.h> 2 #include<string.h> 3 #include<algorithm> 4 #include<stdlib.h> 5 //#include<iostream> 6 using namespace std; 7 8 int n; 9 #define maxn 500011 10 #define maxm 10000011 11 const int mod=1e9+7; 12 int a[maxn]; 13 14 int xiao[maxm],miu[maxm],prime[maxm],lp;bool notprime[maxm]; 15 void pre(int n) 16 { 17 lp=0;notprime[1]=1; 18 for (int i=2;i<=n;i++) 19 { 20 if (!notprime[i]) {prime[++lp]=i;miu[i]=-1;} 21 for (int j=1;j<=lp && 1ll*prime[j]*i<=n;j++) 22 { 23 notprime[prime[j]*i]=1; 24 xiao[prime[j]*i]=prime[j]; 25 if (!(i%prime[j])) {miu[i*prime[j]]=0;break;} 26 else miu[i*prime[j]]=-miu[i]; 27 } 28 } 29 } 30 31 int cnt[maxm],two[maxn]; 32 int frac[15],lf; 33 int main() 34 { 35 scanf("%d",&n);int Max=0; 36 for (int i=1;i<=n;i++) scanf("%d",&a[i]),Max=max(Max,a[i]); 37 two[0]=1;for (int i=1;i<=n;i++) two[i]=(two[i-1]<<1)%mod; 38 pre(Max); 39 for (int i=1;i<=n;i++) 40 { 41 int tmp=a[i];lf=0; 42 while (xiao[tmp]) 43 { 44 int now=xiao[tmp]; 45 while (xiao[tmp]==now) tmp/=xiao[tmp]; 46 frac[++lf]=now; 47 } 48 if (!lf || frac[lf]!=tmp) frac[++lf]=tmp; 49 for (int i=1;i<(1<<lf);i++) 50 { 51 int now=1; 52 for (int j=1;j<=lf;j++) if (i&(1<<(j-1))) now*=frac[j]; 53 cnt[now]++; 54 } 55 } 56 int A=0; 57 for (int i=2;i<=Max;i++) A=(A-miu[i]*(two[cnt[i]]-1))%mod; 58 59 int ans=0; 60 for (int i=1;i<=n;i++) 61 { 62 int tmp=a[i];lf=0; 63 while (xiao[tmp]) 64 { 65 int now=xiao[tmp]; 66 while (xiao[tmp]==now) tmp/=xiao[tmp]; 67 frac[++lf]=now; 68 } 69 if (!lf || frac[lf]!=tmp) frac[++lf]=tmp; 70 int B=0; 71 for (int i=1;i<(1<<lf);i++) 72 { 73 int now=1; 74 for (int j=1;j<=lf;j++) if (i&(1<<(j-1))) now*=frac[j]; 75 B=(B-miu[now]*(two[cnt[now]]-1))%mod; 76 } 77 ans=((ans+A)%mod-B)%mod; 78 } 79 printf("%d\n",(ans+mod)%mod); 80 return 0; 81 }
以上是关于CF585E:Present for Vitalik the Philatelist的主要内容,如果未能解决你的问题,请参考以下文章
cf1322BB. Present(二分/前缀和+按位考虑)
CodeForces585 E. Present for Vitalik the Philatelist