[Noi2015]寿司晚宴

来自FallDream的博客,未经允许,请勿转载,谢谢。


 

为了庆祝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取模)。注意一个人可以不吃任何寿司。

n<=500

 

考虑状压dp,发现500以内的数字最多只会有一个大于19的因数,而19以内的质数只有8个

用f[i][j]表示一个人选的寿司含有质因数的状态是i,另一个人是j的方案数,我们按照大于19的因数排序,同一个因数一起转移即可

复杂度n*2^16

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define pa pair<int,int>
#define mp(x,y) make_pair(x,y)
#define MN 256
using namespace std;
inline int read()
{
    int x = 0; char ch = getchar();
    while(ch < '0' || ch > '9') ch = getchar();
    while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
    return x;
}

int n,P,f[1<<8][1<<8],G[1<<8][1<<8],H[1<<8][1<<8];
const int S[8]={2,3,5,7,11,13,17,19};
pa num[505];

void Solve(int x)
{
    int T=num[x].second;
    for(int i=MN-1;~i;--i)
        for(int j=MN-1;~j;--j)
        {
            int g=G[i][j],h=H[i][j];
            if(!(i&T))
            {
                G[i][j|T]=((G[i][j|T]+g)%P+f[i][j])%P;
                if(num[x].first==1) (G[i][j|T]+=h)%=P;
            }
            if(!(j&T))
            {
                H[i|T][j]=((H[i|T][j]+h)%P+f[i][j])%P;
                if(num[x].first==1) (H[i|T][j]+=g)%=P;
            }
        }
}

int main()
{
    n=read();P=read();
    for(int i=2;i<=n;++i)
    {
        int t=i;
        for(int j=0;j<8;++j)
            for(;!(t%S[j]);num[i].second|=(1<<j))t/=S[j];
        num[i].first=t;
    }
    sort(num+2,num+n+1);
    f[0][0]=1;
    for(int i=2,j;i<=n;i=j)
    {
        memset(G,0,sizeof(G));
        memset(H,0,sizeof(H));
        for(j=i;j<=n&&num[j].first==num[i].first;++j)Solve(j);
        for(int k=0;k<MN;++k)
            for(int l=0;l<MN;++l)
                f[k][l]=((f[k][l]+G[k][l])%P+H[k][l])%P;
    }
    int ans=0;
    for(int i=0;i<MN;++i)
        for(int j=0;j<MN;++j)
            (ans+=f[i][j])%=P;
    printf("%d\n",ans);
    return 0;
}

转载于:https://www.cnblogs.com/FallDream/p/Noi2015d1t3.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值