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
",(ans+mod)%mod);
80     return 0;
81 }
View Code
原文地址:https://www.cnblogs.com/Blue233333/p/7920138.html