其他分享
首页 > 其他分享> > [HNOI2012]集合选数(构造,状态压缩,DP)

[HNOI2012]集合选数(构造,状态压缩,DP)

作者:互联网

神仙题。

莫名其妙的就试一试把所有数放进一个类似矩阵的东西里面。

首先把 \(1\) 放到左上角,然后在每个数的右边放它的 \(3\) 倍(大于 \(n\) 就不用放了),下面放它的 \(2\) 倍(大于 \(n\) 就不用放了)。

注意这样子有些数会不在里面。那么从小到大,每次选最小的且没有出现过的数作为一个新的“矩阵”的左上角。容易发现这些“矩阵”互不干扰,对每个矩阵分别求方案数,乘起来就好了。

对于一个矩阵,发现就是对于一个数,如果它选了,那么它右边和下面的都不能选。

问题就变成选一些数,互不相邻的方案数。

由于这个矩阵不会太大(长和宽都是 \(\log\) 级别的),所以直接状压。

时间复杂度,大力分析一波(我的分析特别松,首先假设所有矩阵都是满的,也就是右下角不会空出一块,然后状压时也不考虑能不能删掉无用状态),会得到一个极其松的上界 \(3\times 10^7\)。状压 DP 时剪掉无用状态,就能跑得飞快了。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int maxn=100010,mod=1000000001;
#define MP make_pair
#define PB push_back
#define lson o<<1,l,mid
#define rson o<<1|1,mid+1,r
#define FOR(i,a,b) for(int i=(a);i<=(b);i++)
#define ROF(i,a,b) for(int i=(a);i>=(b);i--)
#define MEM(x,v) memset(x,v,sizeof(x))
inline ll read(){
    char ch=getchar();ll x=0,f=0;
    while(ch<'0' || ch>'9') f|=ch=='-',ch=getchar();
    while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
    return f?-x:x;
}
int n,ans=1,len[18],f[18][2048],ok[2048],ol;
bool vis[maxn];
bool check(int x){
    FOR(i,0,11) if((x>>i)&(x>>(i+1))&1) return false;
    return true;
}
int solve(int x){
    int y=x,w,s=0;
    FOR(i,1,n){
        if(y>n) break;
        int z=y;
        FOR(j,1,n){
            if(z>n) break;
            len[i]=j;
            vis[z]=true;
            z*=3;
        }
        w=i;
        y*=2;
    }
    FOR(i,1,ol){
        if(ok[i]>=(1<<len[1])) break;
        f[1][i]=1;
        if(w==1) s=(s+1)%mod;
    }
    FOR(i,2,w) FOR(j,1,ol){
        if(ok[j]>=(1<<len[i])) break;
        f[i][j]=0;
        FOR(k,1,ol){
            if(ok[k]>=(1<<len[i-1])) break;
            if(!(ok[j]&ok[k])) f[i][j]=(f[i][j]+f[i-1][k])%mod;
        }
        if(i==w) s=(s+f[i][j])%mod;
    }
    return s;
}
int main(){
    n=read();
    FOR(i,0,2047) if(check(i)) ok[++ol]=i;
    FOR(i,1,n) if(!vis[i]) ans=1ll*ans*solve(i)%mod;
    printf("%d\n",ans);
}

标签:ch,int,选数,ll,状压,矩阵,HNOI2012,DP,define
来源: https://www.cnblogs.com/1000Suns/p/11372204.html