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 }
来源:https://www.cnblogs.com/Blue233333/p/7920138.html
