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

    https://www.luogu.com.cn/problem/P2150

    题解

    前n个数(除去1)分到两组头,两组都要互质。

    考虑30% 质数只有10个就可以状压f[i][j]表示第一组有状态为i的质数,第二组j有好多种方法。

    显然f[i][j&s]+=f[i][j](!(i&s))

    f[i&s][j]+=f[i][j](!(j&s))

    f[0][0]=1;

    考虑100%

    发现500开跟22 22以内质数只有8个,而且超过22的质数不可能有两个出线在同一个数里。那我们记每个数的小质数状态s,大质数da。

    吧所有大质数相同的排在一起,这样来保证这一个大质数只被同一个人选。

    用三个数组转移

    代码如下:

    #include<bits/stdc++.h>
    #define int long long
    using namespace std;
    const int N=505;
    int n,mo,f1[N][N],f2[N][N],dp[N][N],zhi[10]={1,2,3,5,7,11,13,17,19};
    struct pigu
    {
        int da,s;
    }a[N];
    inline int read()
    {
        char c=getchar();
        int x=0,f=1;
        while(!isdigit(c)) {if(c=='-') f=-1;c=getchar();}
        while(isdigit(c)) {x=(x<<3)+(x<<1)+c-'0';c=getchar();}
        return x*f;
    }
    inline int add(int x,int y)
    {
        return x+y>mo?x+y-mo:x+y;
    }
    inline bool cmp(pigu x,pigu y)
    {
        return x.da<y.da;
    }
    signed main()
    {
        n=read();mo=read();
        if(mo==1)
        {
            cout<<"0";
            return 0;
        }
        for(int i=2;i<=n;i++)
        {
            int hu=i;
            for(int j=1;j<=8;j++)
            {
                while(hu%zhi[j]==0)
                {
                    hu/=zhi[j];
                    a[i].s|=(1<<j-1);
                }
            }    
            if(hu!=1) a[i].da=hu;
        }
        dp[0][0]=1;
        sort(a+2,a+n+1,cmp);
        for(int i=2;i<=n;i++)
        {
            if(a[i].da!=a[i-1].da||a[i].da==0)
            {
                for(int j=0;j<=255;j++) 
                    for(int k=0;k<=255;k++)
                        f1[j][k]=f2[j][k]=dp[j][k];
            }
            for(int j=255;j>=0;j--)
                for(int k=255;k>=0;k--)
                    if(!(j&k))
                    {
                        if(!(j&a[i].s)) f2[j][k|a[i].s]=add(f2[j][k|a[i].s],f2[j][k]);
                        if(!(k&a[i].s)) f1[j|a[i].s][k]=add(f1[j|a[i].s][k],f1[j][k]);
                    }
            if(a[i].da!=a[i+1].da||a[i].da==0||i==n)
            {
                for(int j=0;j<=255;j++)
                    for(int k=0;k<=255;k++)
                        if(!(j&k))
                        {
                            dp[j][k]=add(mo-dp[j][k],add(f1[j][k],f2[j][k]));
                        }
            }
        }
        int ans=0;
        for(int i=0;i<=255;i++) for(int j=0;j<=255;j++) if(!(i&j))ans=add(ans,dp[i][j]);
        cout<<ans;
    }
    View Code
  • 相关阅读:
    MongoDB Replica Set 选举过程
    转 Warning:MongoDB Replica Sets配置注意事项
    mongodb与内存
    mongodb的监控与性能优化
    php 5.5.1 编译安装过程
    java知识点积累(一)
    java内存及数据区
    static及静态方法
    接口和抽象类
    Java SE自学阶段的笔记整理
  • 原文地址:https://www.cnblogs.com/betablewaloot/p/12339756.html
Copyright © 2011-2022 走看看