1. 程式人生 > >CF585E:Present for Vitalik the Philatelist

CF585E:Present for Vitalik the Philatelist

就是 tel clas res list lib 技術 closed sed

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 }
View Code

CF585E:Present for Vitalik the Philatelist