$n \leq 500$,$2-n$这些数字,两个人挑,可以重复挑,问有几种方案中,一个人选的所有数字与另一个人选的所有数字都互质。
不像前两题那么抠脚。。
如果$n$比较小的话,可以把两个人选的数字对应的质因子状压一下,$f(i,j,k)$--前$i$个数,第一个人选状态$j$,第二个人选状态$k$,状态表示质因子。
质因子的根号相关性质:根号n之后的每个质因子最多只会在一个数里出现一次。也就是说,对根号n前面的质因子我们是可能一次选若干种的,但根号n后面的每个质因子每次只能选一种,所以可以单独枚举,再用根号n以前的状态表示。$g(i,j,k)$--前$i$个含质数$p$的数,只让第一个人选,第二个人保持状态$k$的方案数;$h(i,j,k)$--前$i$个含质数$p$的数,只让第二个人选,第一个人保持状态$j$的方案数。如此dp完,$ans(j,k)$表示最后的$f(i,j,k)$,那么$ans(j,k)=g(t,j,k)+h(t,j,k)-ans(j,k)$,其中$t$表示含质因数$p$的数的个数,因为两个人都不选的方案算了两次。

1 //#include<iostream>
2 #include<cstring>
3 #include<cstdio>
4 //#include<math.h>
5 //#include<set>
6 //#include<queue>
7 //#include<bitset>
8 //#include<vector>
9 #include<algorithm>
10 #include<stdlib.h>
11 using namespace std;
12
13 #define LL long long
14 int qread()
15 {
16 char c; int s=0,f=1; while ((c=getchar())<'0' || c>'9') (c=='-') && (f=-1);
17 do s=s*10+c-'0'; while ((c=getchar())>='0' && c<='9'); return s*f;
18 }
19
20 //Pay attention to '-' , LL and double of qread!!!!
21
22 int n,mod;
23 #define maxn 555
24 int f[2][maxn][maxn],g[2][maxn][maxn],h[2][maxn][maxn],cur=0;
25
26 int prime[maxn],lp,xx[maxn],ss[maxn]; bool notprime[maxn];
27 void makeprime()
28 {
29 ss[2]=0; ss[3]=1; ss[5]=2; ss[7]=3;
30 ss[11]=4; ss[13]=5; ss[17]=6; ss[19]=7;
31 for (int i=2;i<=n;i++)
32 {
33 if (!notprime[i]) {prime[++lp]=i; xx[i]=i;}
34 for (int j=1,tmp;j<=lp && 1ll*i*prime[j]<=n;j++)
35 {
36 notprime[tmp=i*prime[j]]=1;
37 xx[tmp]=prime[j];
38 if (!(i%prime[j])) break;
39 }
40 }
41 }
42
43 int num[maxn],len; int S,P;
44 void mm(int x)
45 {
46 len=0;
47 while (x>1) {num[++len]=xx[x]; x/=xx[x];}
48 sort(num+1,num+1+len); len=unique(num+1,num+1+len)-num-1;
49 S=0; for (int i=1;i<=len;i++) if (num[i]<=19) S|=1<<ss[num[i]];
50 if (num[len]>19) P=num[len]; else P=0;
51 }
52
53 int list[maxn][maxn];
54 void play(int &x,int v) {x+=v; x-=x>=mod?mod:0;}
55 int main()
56 {
57 n=qread(); mod=qread();
58 makeprime();
59 for (int i=2;i<=n;i++) {mm(i); list[P][++list[P][0]]=S;}
60
61 int ts=1<<8; f[0][0][0]=1; cur=0;
62 for (int i=1;i<=list[0][0];i++)
63 {
64 int u=list[0][i];
65 memset(f[cur^1],0,sizeof(f[cur^1]));
66 for (int j=0;j<ts;j++)
67 for (int k=0;k<ts;k++) if (f[cur][j][k])
68 {
69 play(f[cur^1][j][k],f[cur][j][k]);
70 int nj=j|u; if ((nj&k)==0) play(f[cur^1][nj][k],f[cur][j][k]);
71 int nk=k|u; if ((j&nk)==0) play(f[cur^1][j][nk],f[cur][j][k]);
72 }
73 cur^=1;
74 }
75
76 for (int j=0;j<ts;j++)
77 for (int k=0;k<ts;k++)
78 f[0][j][k]=f[cur][j][k];
79 for (int i=2;i<=n;i++) if (!notprime[i])
80 {
81 cur=0;
82 for (int j=0;j<ts;j++)
83 for (int k=0;k<ts;k++)
84 g[0][j][k]=f[0][j][k],h[0][j][k]=f[0][j][k];
85 for (int t=1;t<=list[i][0];t++)
86 {
87 int u=list[i][t];
88 memset(g[cur^1],0,sizeof(g[cur^1]));
89 memset(h[cur^1],0,sizeof(h[cur^1]));
90 for (int j=0;j<ts;j++)
91 for (int k=0;k<ts;k++) if (g[cur][j][k])
92 {
93 play(g[cur^1][j][k],g[cur][j][k]);
94 int nj=j|u; if ((nj&k)==0) play(g[cur^1][nj][k],g[cur][j][k]);
95 }
96 for (int j=0;j<ts;j++)
97 for (int k=0;k<ts;k++) if (h[cur][j][k])
98 {
99 play(h[cur^1][j][k],h[cur][j][k]);
100 int nk=k|u; if ((j&nk)==0) play(h[cur^1][j][nk],h[cur][j][k]);
101 }
102 cur^=1;
103 }
104 for (int j=0;j<ts;j++)
105 for (int k=0;k<ts;k++)
106 f[0][j][k]=((g[cur][j][k]+h[cur][j][k]-f[0][j][k])%mod+mod)%mod;
107 }
108
109 int ans=0;
110 for (int j=0;j<ts;j++)
111 for (int k=0;k<ts;k++)
112 play(ans,f[0][j][k]);
113 printf("%d\n",ans);
114 return 0;
115 }
来源:https://www.cnblogs.com/Blue233333/p/9286405.html
