先理解一下題目吧:
兩人所選數的質因數集合不能有交集,
<=30的質數只有10個,因此能夠直接狀壓,
\(dp[i][j]\)表明第一我的選的狀態爲i,第二我的的狀態爲j的方案數,
100%:n由30拓展到了500,怎麼辦?
考慮到<=500的數最多隻有1個大於\(sqrt(500)>22\)的大質因子,
咱們能夠按大質因子排序,想同的大質因子裏用,用dp表示選了它的狀況,用dp2表示沒選的狀況,而後轉移,
不一樣的時候就繼承以前的值.c++
#include<bits/stdc++.h> #define ll long long using namespace std; const int M=506,N=266; int n,m,tot=0,book[M],prime[M]; ll ans=0,p,f[N][N],dp[N][N],dp2[N][N]; struct xd{int a,b;}q[M]; void init(){ for(int i=2;i<=500;++i){ if(!book[i]) prime[++tot]=i; for(int j=1;j<=tot&&i*prime[j]<=500;++j){ book[i*prime[j]]=1; if(i%prime[j]==0) break; } } } bool cmp(xd u,xd v){return u.b<v.b;} int main(){ scanf("%d%lld",&n,&p),m=255,init(); for(int i=2;i<=n;++i){ for(int j=9;j<=tot;++j) if(i%prime[j]==0) q[i-1].b=prime[j]; for(int j=0;j<=7;++j) if(i%prime[j+1]==0) q[i-1].a+=(1<<j); } sort(q+1,q+n,cmp),f[0][0]=1,q[0].b=q[n].b=-1; for(int i=1;i<n;++i){ if(q[i].b!=q[i-1].b||!q[i].b) memcpy(dp,f,sizeof(dp)),memcpy(dp2,f,sizeof(dp2)); for(int j=m;j>=0;--j) for(int k=m;k>=0;--k){ if(j&k) continue; if(!(q[i].a&k)) dp[j|q[i].a][k]=(dp[j|q[i].a][k]+dp[j][k])%p; if(!(q[i].a&j)) dp2[j][k|q[i].a]=(dp2[j][k|q[i].a]+dp2[j][k])%p; } if(q[i].b!=q[i+1].b||!q[i].b) for(int j=m;j>=0;--j) for(int k=m;k>=0;--k) f[j][k]=(dp[j][k]+dp2[j][k]-f[j][k]+p)%p; } for(int i=m;i>=0;--i) for(int j=m;j>=0;--j) ans=(ans+f[i][j])%p; printf("%lld\n",ans); return 0; }