bzoj 4197: [Noi2015]壽司晚宴【狀壓dp】
阿新 • • 發佈:2018-09-25
memcpy [] 正常 can != 多個 \n ios int
一個數內可能多個的質因數只有小於根號n的,500內這樣的數只有8個,所以考慮狀壓
把2~n的數處理出小於根號500的質因數集壓成s,以及大質數p(沒有就是1),然後按p排序
根據題目要求,擁有一個質因數的只能給一個人,所以排序後能給一個人的大質數就是一個區間
然後設f[s1][s2]為一人選s1,另一人選s2的方案數,註意這裏的s只壓了小於根號500的八個質數
設g[0/1][s1][s2]為一人選s1,另一人選s2的,當前枚舉的大質數給小G/小W的方案數
正常轉移即可
然後註意把g轉到f上時應該是f[j][k]=g[0][j][k]+g[1][j][k]-f[j][k],也就是減掉被算了兩次的,當前枚舉大質數都不選的情況
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> using namespace std; const int N=505,p[]={2,3,5,7,11,13,17,19}; int n; long long mod,f[N][N],g[2][N][N],ans; bool v[N]; struct qwe { int s,p; }a[N]; bool cmp(const qwe &a,const qwe &b) { return a.p<b.p; } int main() { scanf("%lld%lld",&n,&mod); for(int i=2;i<=n;i++) { int x=i; for(int j=0;j<8;j++) if(x%p[j]==0) { a[i].s|=(1<<j); while(x%p[j]==0) x/=p[j]; } a[i].p=x; } sort(a+2,a+1+n,cmp); f[0][0]=1; for(int i=2;i<=n;i++) { if(i==2||a[i].p!=a[i-1].p||a[i].p==1) { memcpy(g[0],f,sizeof(f)); memcpy(g[1],f,sizeof(f)); } for(int j=255;j>=0;j--) for(int k=255;k>=0;k--) if(!(j&k)) { if(!(a[i].s&k)) g[0][a[i].s|j][k]=(g[0][a[i].s|j][k]+g[0][j][k])%mod; if(!(a[i].s&j)) g[1][j][a[i].s|k]=(g[1][j][a[i].s|k]+g[1][j][k])%mod; } if(i==n||a[i].p==1||a[i].p!=a[i+1].p) for(int j=255;j>=0;j--) for(int k=255;k>=0;k--) if(!(j&k)) f[j][k]=(g[0][j][k]+g[1][j][k]-f[j][k])%mod; } for(int i=255;i>=0;i--) for(int j=255;j>=0;j--) if(!(i&j)) ans=(ans+f[i][j])%mod; printf("%lld\n",(ans+mod)%mod); return 0; }
bzoj 4197: [Noi2015]壽司晚宴【狀壓dp】