zoukankan      html  css  js  c++  java
  • [NOI2015]寿司晚宴(状压dp)

    为了庆祝NOI的成功开幕,主办方为大家准备了一场寿司晚宴。小G和小W作为参加NOI的选手,也被邀请参加了寿司晚宴。

    在晚宴上,主办方为大家提供了n−1种不同的寿司,编号1,2,3,⋯,n-1,其中第种寿司的美味度为i+1(即寿司的美味度为从2到n)。

    现在小G和小W希望每人选一些寿司种类来品尝,他们规定一种品尝方案为不和谐的当且仅当:小G品尝的寿司种类中存在一种美味度为x的寿司,小W品尝的寿司中存在一种美味度为y的寿司,而x与y不互质。

    现在小G和小W希望统计一共有多少种和谐的品尝寿司的方案(对给定的正整数p取模)。注意一个人可以不吃任何寿司。

    Solution

    题意:有1-n-1这些数,把他们分给两个人(可以不分),使得从两个人各自任意拿出一个数,它们都是互质的。

    注意到n是500,范围内小质数较少,可以考虑状压小质数。

    但是大质数怎么处理?

    我们可以设计状态为dp[i][j]表示做到了第i个大质数,当前小质数的选择情况为j时的方案数。

    因为每个大质数只能给一个人,所以我们dp的阶段就是每个大质数。

    最后统计答案时要注意,我们把都没选的情况考虑了两次,把多余的部分减去就可以了。

    Code

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #define N 509
    #define R register 
    using namespace std;
    int prime[N],mdiv[N],n,k,size,ma;
    long long g[2][1<<9][1<<9],f[1<<9][1<<9],mod,ans;
    struct aaa
    {
        int a,b;
    }ji[N];
    bool cmp(aaa a,aaa b)
    {
        return a.b<b.b;
    }
    int main()
    {
        scanf("%d%lld",&n,&mod);
        for(R int i=2;i<=n;++i)
          {
            if(!mdiv[i])mdiv[i]=i,prime[++prime[0]]=i;
            for(R int j=1;j<=prime[0]&&((k=prime[j]*i)<=n);++j)
            {
              mdiv[k]=prime[j];
              if(i%prime[j]==0)break;
            }
          }
        size=min(prime[0],9);
        for(R int i=2;i<=n;++i){
            int tmp=i;
            for(R int j=1;j<=size;++j)
              if(!(tmp%prime[j]))
              {
                  while(!(tmp%prime[j]))tmp/=prime[j];
                  ji[i].a|=(1<<j-1);
              }
            ji[i].b=tmp;
        }
        sort(ji+2,ji+n+1,cmp);
        ma=(1<<size)-1;
        f[0][0]=1; 
        for(R int i=2;i<=n;++i){
            if((ji[i].b==1)||(ji[i].b!=ji[i-1].b)){
                for(R int j=0;j<=ma;++j)
                  for(R int k=0;k<=ma;++k)
                    g[0][j][k]=g[1][j][k]=f[j][k];
            }
            for(R int j=ma;j>=0;--j)
              for(R int k=ma;k>=0;--k)
              if(!(j&k)){
                    if(!(ji[i].a&j))(g[0][j][k|ji[i].a]+=g[0][j][k])%=mod;
                    if(!(ji[i].a&k))(g[1][j|ji[i].a][k]+=g[1][j][k])%=mod;
                }
            if((ji[i].b==1)||(ji[i].b!=ji[i+1].b))
            for(R int j=0;j<=ma;++j)
              for(R int k=0;k<=ma;++k)
                if(!(j&k))
                  f[j][k]=(g[0][j][k]+g[1][j][k]-f[j][k]+mod)%mod;
       }
        for(R int i=0;i<=ma;++i)
          for(R int j=0;j<=ma;++j)
          if(!(i&j))
            (ans+=f[i][j])%=mod;
        cout<<ans;
        return 0;
    } 
  • 相关阅读:
    php项目目录显示
    初识fastadmin
    php环境变量
    tp5数据库——时间查询
    tp5数据库——聚合查询
    tp5数据库——链式操作
    tp5数据库——查询语法
    MongoDB踩坑记录
    RxJS合并操作符:concat、merge、forkJoin、zip、 combineLatest 、concatAll、mergeAll、switchAll
    Git Flow
  • 原文地址:https://www.cnblogs.com/ZH-comld/p/9698442.html
Copyright © 2011-2022 走看看