luogu2150 [NOI2015]寿司晚宴
https://www.luogu.com.cn/problem/P2150
考虑对于2~n,
把出现次数大于1的质数拎出来,只有2 3 5 7 11 13 17 19 共8个
剩下的质数记为x,我们把所有数按x排序。
1.x=1
这个数给谁都不会被大质数限制当成一个新的x处理。
2.x>1
那么x相同的那一些数只能给同一个人。
分成f,g分别dp
#include<cstdio> #include<iostream> #include<cstdlib> #include<cstring> #include<algorithm> #include<cmath> #define M (1<<8)+5 using namespace std; int n,Max=(1<<8)-1; long long mod,f[M][M],g[M][M],dp[M][M]; int p[8]={2,3,5,7,11,13,17,19}; struct node{ int v,k; void fj(int x){ v=x;k=0; for(int i=0;i<8;i++){ if(v%p[i]==0)k+=(1<<i); while(v%p[i]==0)v=v/p[i]; } } }s[505]; bool cmp(node A,node B){return A.v<B.v;} int main(){ cin>>n>>mod;n--; for(int i=1;i<=n;i++)s[i].fj(i+1); sort(s+1,s+n+1,cmp); dp[0][0]=f[0][0]=g[0][0]=1; for(int x=1;x<=n;x++){ if(s[x].v!=s[x-1].v||s[x].v==1){ for(int i=Max;i>=0;i--) for(int j=Max;j>=0;j--){ dp[i][j]=(f[i][j]+g[i][j]-dp[i][j])%mod; f[i][j]=g[i][j]=dp[i][j]; } } for(int i=Max;i>=0;i--) for(int j=Max;j>=0;j--){ if(!(i&s[x].k))(f[i][j|s[x].k]+=f[i][j])%=mod; if(!(j&s[x].k))(g[i|s[x].k][j]+=g[i][j])%=mod; } } for(int i=Max;i>=0;i--) for(int j=Max;j>=0;j--){ dp[i][j]=(f[i][j]+g[i][j]-dp[i][j])%mod; f[i][j]=g[i][j]=dp[i][j]; } long long ans=0; for(int i=0;i<=Max;i++) for(int j=0;j<=Max;j++)ans=(ans+dp[i][j])%mod; ans=(ans+mod)%mod; cout<<ans<<endl; return 0; }