【BZOJ】4197: [Noi2015]寿司晚宴-状压DP

传送门:bzoj4197


题解

状压dp了解一下。 500 以下的质数就八个,其他特殊因数用pair存。状态转移要注意。


代码

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<vector>
#define N (1<<8)
#define mp make_pair
#define fr first
#define sc second
using namespace std;
int n,r,p;
int y[10]={2,3,5,7,11,13,17,19};
int f[260][260],g[2][260][260],ans;
pair<int,int>q[505];
inline void mo(int& x){if(x>=p) x%=p;else if(x<0) x+=p;}//x -> &x
int main(){
    scanf("%d%d",&n,&p);
    for(int x,z,j,i=2;i<=n;i++){
        x=i;z=0;
        for(j=0;j<8 && x!=1;j++){
            if(x%y[j]==0){
                while(x%y[j]==0) x/=y[j];
                z|=(1<<j);
            }
        }
        q[i].fr=x;q[i].sc=z;
    }
    sort(q+2,q+n+1);
    f[0][0]=1;
    for(int i=2;i<=n;i++){
        if(i==2 || q[i].fr==1 || q[i].fr != q[i-1].fr){
            for(int j=0;j<N;j++)
            for(int k=0;k<N;k++)
            g[0][j][k]=g[1][j][k]=f[j][k];
        }
        for(int j=N-1;j>=0;j--){
            for(int k=N-1;k>=0;k--){
                if((k&q[i].sc)==0) mo(g[0][j|q[i].sc][k]+=g[0][j][k]);
                if((j&q[i].sc)==0) mo(g[1][j][k|q[i].sc]+=g[1][j][k]);
            } 
        }
        if(i==n || q[i].fr==1 || q[i].fr!=q[i+1].fr){
            for(int j=N-1;j>=0;j--){
               for(int k=N-1;k>=0;k--){
                 mo(f[j][k]=g[0][j][k]+g[1][j][k]-f[j][k]);
               } 
            } 
        }
    }
    for(int i=0;i<N;i++)
     for(int j=0;j<N;j++)
     if((i&j)==0) mo(ans+=f[i][j]);
     //i&j==0 -> (i&j)==0
    printf("%d\n",(ans%p+p)%p);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/corsica6/article/details/80373562