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;
}
View Code

 

posted @ 2020-02-19 23:17  liankewei123456  阅读(159)  评论(0编辑  收藏  举报