bzoj2734: [HNOI2012]集合选数

把大视野的老爷机卡了10分钟。。。只是发现数组开小了,然后一手贱又开的很大。。。

这题思路很妙啊。

就是写出很多矩阵,对于一个位置的值x,右边的是3x,下边是2x,然后相邻的不能同取。%这dalao题解吧

然后状压DP(我能说一开始算错复杂度一脸蒙蔽)

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long LL;
const LL mod=1000000001;

int n;
bool v[1100000];
int len[1100];
LL f[20][210000];
int solve(int x)
{
    memset(len,0,sizeof(len));
    int zzz=x,L=0;
    for(int i=1;zzz<=n;i++)
    {
        int zgx=zzz;
        for(int j=1;zgx<=n;j++)
        {
            v[zgx]=true;
            zgx*=2;
            len[i]=j;
        }
        zzz*=3;
        L=i;
    }
    
    //make the matrix
    
    
    
    len[0]=1;
    for(int i=0;i<=L;i++)
        for(int j=0;j<(1<<len[i]);j++)f[i][j]=0;
    len[L+1]=0,f[L+1][0]=0;
    f[0][0]=1;
    //init
    
    for(int i=0;i<=L;i++)
    {
        for(int j=0;j<(1<<len[i]);j++)
        {
            if(f[i][j]!=0)
            {
                if((j&(j>>1))>0)continue;
                for(int k=0;k<(1<<len[i+1]);k++)
                {
                    if((j&k)>0)continue;
                    f[i+1][k]=(f[i+1][k]+f[i][j])%mod;
                }
            }
        }
    }
    return f[L+1][0];
}

int main()
{
    scanf("%d",&n);
    memset(v,false,sizeof(v));
    LL ans=1;
    for(int i=1;i<=n;i++)
        if(v[i]==false)ans=(ans*solve(i))%mod;
    printf("%lld\n",ans);
    return 0;
}

 

posted @ 2018-03-16 14:09  AKCqhzdy  阅读(179)  评论(0编辑  收藏  举报