zoukankan      html  css  js  c++  java
  • BZOJ2734 HNOI2012集合选数(状压dp)

      完全想不到的第一步是构造一个矩阵,使得每行构成公比为3的等比数列,每列构成公比为2的等比数列。显然矩阵左上角的数决定了这个矩阵,只要其取遍所有既不被2也不被3整除的数那么所得矩阵的并就是所有的数了,并且显然不会有重复。

      现在要满足题目要求只需要使在矩阵中选取的数不相邻。显然这可以用状压dp以4^n*m的复杂度搞出来。对于每一个矩阵都这样做一遍再乘起来就可以了。

      看起来复杂度非常爆炸。不过冷静分析一下,这样做的复杂度往大了算是Σ4log3(n/i)*log2n,即Σ(n/i)*log34*log2n,也即复杂度不会超过O(nlog2n)。当然远远跑不满。

    #include<iostream> 
    #include<cstdio>
    #include<cmath>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int read()
    {
        int x=0,f=1;char c=getchar();
        while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
        while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
        return x*f;
    }
    #define P 1000000001
    #define N 100010
    int n,len[20],p[20],lg3[N],f[20][1<<17],q[1<<17],cnt=0,ans=1;
    int main()
    {
    #ifndef ONLINE_JUDGE
        freopen("bzoj2734.in","r",stdin);
        freopen("bzoj2734.out","w",stdout);
        const char LL[]="%I64d
    ";
    #else
        const char LL[]="%lld
    ";
    #endif
        n=read();
        p[1]=1;for (int i=2;i<=15;i++) p[i]=p[i-1]*3;
        lg3[1]=1;
        for (int i=2;i<=n;i++)
        {
            lg3[i]=lg3[i-1];
            if (p[lg3[i]+1]<=i) lg3[i]++;
        }
        for (int i=0;i<(1<<17);i++)
        {
            int x=i,last=0;q[++cnt]=i;
            while (x)
            {
                if ((x&1)&&last) {cnt--;break;}
                last=x&1;x>>=1;
            }
        }
        q[cnt+1]=1<<17;
        for (int i=1;i<=n;i++)
        if (i%2&&i%3)
        {
            int m;
            for (m=1;(i<<m-1)<=n;m++) len[m]=lg3[n/(i<<m-1)];
            m--;
            f[0][1]=1;
            for (int k=1;k<=m;k++)
                for (int j=1;q[j]<(1<<len[k]);j++)
                {
                    f[k][j]=0;
                    for (int x=1;q[x]<(1<<len[k-1]);x++)
                    if (!(q[j]&q[x])) f[k][j]=(f[k][j]+f[k-1][x])%P;
                }
            int tot=0;
            for (int j=1;q[j]<(1<<len[m]);j++) tot=(tot+f[m][j])%P;
            ans=1ll*ans*tot%P;
        }
        cout<<ans;
        return 0;
    }
  • 相关阅读:
    人的一生为什么要努力 &1
    数据库_数据库系统概论
    电子商务安全
    虚拟专用网技术
    人的一生为什么要努力
    数据备份与恢复技术
    入侵检测技术
    简历模板连接
    防火墙技术
    字节与位
  • 原文地址:https://www.cnblogs.com/Gloid/p/9603926.html
Copyright © 2011-2022 走看看