• NOI2015 寿司晚宴


    题目链接:戳我

    30pts还是很好写的,因为30以内的质因数就没有几个,直接状压就可以了.
    但是如果范围扩大到500呢?我们考虑后面的数怎么处理.

    首先观察到19之后的数最多只能出现一次,那么我们直接状压这前八个质数就行了.后面的我们可以手动添加一下(为了方便,对于当前遍历的值,下面我们称前八个为小因数,后面的为大因数)

    处理出来每个数的小因数的状态,方便下面转移.同时也处理出来它的大因数.而且我们知道大因数应该排序一下(因为相同的肯定要一起处理)--->大概就是一个分块的思想,因为一个质因数只能放到一个集合中.

    具体来讲,是开一个数组(dp[i][j])表示A状态为i,B状态为j,方案数.然后两个辅助数组(f1[i][j])表示A状态为i,B状态为j,当前这个数的大因数给了A,(f2[i][j])表示A状态为i,B状态为j,当前这个数的大因数给了B.

    (f1[dep][i|now_s][j]+=f1[dep-1][i][j])
    (f2[dep][i][j|now_s]+=f2[dep-1][i][j])

    这个过程可以用滚动数组,或者从后往前更新来消除后效性.

    处理完只有小因数的数(他们的大因数为0,排在前面)之后,我们用(f1[i][j],f2[i][j])去更新(dp[i][j])

    (dp[i][j]=f1[i][j]+f2[i][j]-dp[i][j])
    (注意这不是一个方程qwq)

    为什么后面要减去呢?因为我们现在是想综合当前这个大因数放到两个集合中的情况总和,加起来的话,前面([i][j])的情况就算重了QAQ......然后每次在和后面的那个数的大因数不一样的时候就这样更新一下.就可以了.

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define MAXN 255
    using namespace std;
    int n,mod;
    int prime[8]={2,3,5,7,11,13,17,19};
    long long ans;
    long long dp[MAXN+10][MAXN+10],f1[MAXN+10][MAXN+10],f2[MAXN+10][MAXN+10];
    struct Node{int op,s;}node[510];
    inline bool cmp(Node x,Node y){return x.op<y.op;}
    int main()
    {
        #ifndef ONLINE_JUDGE
        freopen("ce.in","r",stdin);
        // freopen("ce.out","w",stdout);
        #endif
        scanf("%d%d",&n,&mod);
        for(int i=2;i<=n;i++)
        {
            int cur=i;
            for(int j=0;j<8;j++)
            {
                if(cur%prime[j]==0)
                {
                    node[i].s|=(1<<j);
                    while(cur&&cur%prime[j]==0) cur/=prime[j];
                }
            }
            node[i].op=cur;
            // printf("i=%d op=%d s=%d
    ",i,node[i].op,node[i].s);
        }
        sort(&node[2],&node[n+1],cmp);
        dp[0][0]=f1[0][0]=f2[0][0]=1;
        for(int id=2;id<=n;id++)
        {
            for(int i=MAXN;i>=0;i--)
                for(int j=MAXN;j>=0;j--)
                {
                    if((i&j)!=0) continue;
                    if((j&node[id].s)==0) f1[i|node[id].s][j]=(f1[i|node[id].s][j]+f1[i][j])%mod;
                    if((i&node[id].s)==0) f2[i][j|node[id].s]=(f2[i][j|node[id].s]+f2[i][j])%mod;
                }
            if(node[id].op==1||(node[id].op!=node[id+1].op))
            {
                // cout<<id<<endl;
                for(int i=0;i<=MAXN;i++)
                    for(int j=0;j<=MAXN;j++)
                        if((i&j)==0)
                            dp[i][j]=(f1[i][j]+f2[i][j]+mod-dp[i][j])%mod;
                memcpy(f1,dp,sizeof(dp));
                memcpy(f2,dp,sizeof(dp));
            }
        }
        for(int i=0;i<=MAXN;i++)
            for(int j=0;j<=MAXN;j++)
                if((i&j)==0)
                    ans=(ans+dp[i][j])%mod;
        printf("%lld
    ",ans);
        return 0;
    }
    
  • 相关阅读:
    管理原则与设计原则
    UI事件与内容,舞台与演员
    知识的分类
    我们头脑中的信息是用来帮助判断和选择的
    管理过程实质是信息过程
    20155201 2016-2017-2 《Java程序设计》第八周学习总结
    20155201 2016-2017-2 《Java程序设计》第七周学习总结
    20155201 2016-2017-2 《Java程序设计》第六周学习总结
    20155201 2016-2017-2 《Java程序设计》第五周学习总结
    20155201 2016-2017-2 《Java程序设计》第四周学习总结
  • 原文地址:https://www.cnblogs.com/fengxunling/p/10947452.html
Copyright © 2020-2023  润新知