「NOI2015」寿司晚宴 解题报告

「NOI2015」寿司晚宴

这个题思路其实挺自然的,但是我太傻了...最开始想着钦定一些,结果发现假了..

首先一个比较套路的事情是状压前8个质数,后面的只会在一个数出现一次的再想办法就好。

然后发现有个重要的事情是后面每个质因子\(x\)做统计的时候都是独立的,那么单独做就好了

显然要压两个人的前面质因子集合\(f_{i,j}\)代表两个人分别是\(i,j\)集合的答案,然后一块一块的加后面的质因子就好

加每一块时,我们显然需要处理谁选择了这一块或者都没选,再搞个\(dp_{0/1,i,j}\)钦定一下谁选,随便转移一下就好了


Code:

#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
template <class T>
void read(T &x)
{
    x=0;char c=getchar();
    while(!isdigit(c)) c=getchar();
    while(isdigit(c)) x=x*10+c-'0',c=getchar();
}
const int N=510;
const int pri[9]={0,2,3,5,7,11,13,17,19};
int n,m,p,dp[2][1<<8][1<<8],f[1<<8][1<<8];
inline int add(int a,int b){return a+b>=p?a+b-p:a+b;}
inline int mul(int a,int b){return 1ll*a*b%p;}
struct num
{
    int s,pri;
    bool friend operator <(num a,num b){return a.pri<b.pri;}
}yuu[N];
int main()
{
    read(n),read(p);
    for(int i=2;i<=n;i++)
    {
        yuu[i].pri=i;
        for(int j=1;j<=8;j++)
            if(i%pri[j]==0)
            {
                yuu[i].s|=1<<j-1;
                while(yuu[i].pri%pri[j]==0) yuu[i].pri/=pri[j];
            }
    }
    std::sort(yuu+2,yuu+n+1);
    f[0][0]=1;int U=(1<<8)-1;
    for(int i=2;i<=n;i++)
    {
        if(yuu[i].pri!=yuu[i-1].pri||yuu[i].pri==1)
        {
            memcpy(dp[0],f,sizeof f);
            memcpy(dp[1],f,sizeof f);
        }
        int sta=yuu[i].s;
        for(int s=U;~s;s--)
            for(int t=U;~t;t--)
                if(!(s&t))
                {
                    if(!(t&sta)) dp[0][s|sta][t]=add(dp[0][s|sta][t],dp[0][s][t]);
                    if(!(s&sta)) dp[1][s][t|sta]=add(dp[1][s][t|sta],dp[1][s][t]);
                }
        if(yuu[i].pri!=yuu[i+1].pri||yuu[i].pri==1)
        {
            for(int s=0;s<=U;s++)
                for(int t=0;t<=U;t++)
                    if(!(s&t))
                        f[s][t]=add(add(dp[0][s][t],dp[1][s][t]),p-f[s][t]);
        }
    }
    int ans=0;
    for(int s=0;s<=U;s++)
        for(int t=0;t<=U;t++)
            ans=add(ans,f[s][t]);
    printf("%d\n",ans);
    return 0;
}

2019.3.4

转载于:https://www.cnblogs.com/butterflydew/p/10472085.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值