zoukankan      html  css  js  c++  java
  • p2150 [NOI2015]寿司晚宴

    传送门

    分析

    我们发现对于大于$sqrt(n)$的数每个数最多只会包含一个

    所以我们把每个数按照大质数的大小从小到大排序

    我们知道对于一种大质数只能被同一个人取

    所以f1表示被A取,f2表示被B取

    最终答案就是这两个的答案减去啥都不去的答案

    因为啥都不去会被重复记录两次

    对于小质数则直接状压转移即可

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<string>
    #include<algorithm>
    #include<cctype>
    #include<cmath>
    #include<cstdlib>
    #include<ctime>
    #include<queue>
    #include<vector>
    #include<set>
    #include<map>
    #include<stack>
    using namespace std;
    #define int long long
    const int p1[] = {0,2,3,5,7,11,13,17,19};
    const int cnt1 = 8;
    int dp[500][500],n,mod,f1[500][500],f2[500][500];
    struct node {
        int msk,ano;
    };
    node d[1100];
    inline void init(int x){
        int res=x+1;
        for(int i=1;i<=cnt1;i++){
          if(res==1)break;
          if(res%p1[i]==0)d[x].msk|=(1<<(i-1));
          while(res%p1[i]==0)res/=p1[i];
        }
        d[x].ano=res;
    }
    inline bool cmp(const node x,const node y){return x.ano<y.ano;}
    signed main(){
        int i,j,k,p,q;
        scanf("%lld%lld",&n,&mod);
        n--;
        for(i=1;i<=n;i++)init(i);
        sort(d+1,d+n+1,cmp);
        dp[0][0]=1;
        for(i=1;i<=n;i++){
          if(d[i].ano==1||d[i].ano!=d[i-1].ano){
              memcpy(f1,dp,sizeof(f1));
              memcpy(f2,dp,sizeof(f2));
          }
          for(j=(1<<8)-1;j>=0;j--)
            for(k=(1<<8)-1;k>=0;k--)if(!(j&k)){
              int msk1=j|d[i].msk,msk2=k|d[i].msk;
              if(!(msk1&k))f1[msk1][k]=(f1[msk1][k]+f1[j][k])%mod;
              if(!(msk2&j))f2[j][msk2]=(f2[j][msk2]+f2[j][k])%mod;
            }
          if(d[i].ano==1||d[i].ano!=d[i+1].ano||i==n){     
            for(j=(1<<8)-1;j>=0;j--)
              for(k=(1<<8)-1;k>=0;k--)if(!(j&k)){
                dp[j][k]=(-dp[j][k]+mod)%mod;
                dp[j][k]=(dp[j][k]+f1[j][k])%mod;
                dp[j][k]=(dp[j][k]+f2[j][k])%mod;
              }
          }
        }
        int Ans=0;
        for(j=0;j<(1<<8);j++)
          for(k=0;k<(1<<8);k++)
            if(!(j&k))Ans=(Ans+dp[j][k])%mod;
        cout<<Ans;
        return 0;
    }
  • 相关阅读:
    PHP中的error
    回调函数与PHP实例
    PHP的基本入门知识
    Java script OOP——浅谈
    实现单行或多行文本溢出显示省略号
    ECharts
    session management会话管理的原理
    easyui 入门指南
    H5视频/音频
    CSS清除浮动各种方法
  • 原文地址:https://www.cnblogs.com/yzxverygood/p/10439144.html
Copyright © 2011-2022 走看看