BZOJ 3195: [Jxoi2012]奇怪的道路(状压dp)

f[i][j][s]表示当前处理第i个点,前i-1个点已连j条边,第i个点开始k个点的奇偶性状态。

#include<cstring>
#include<algorithm>
#include<iostream>
#include<cstdio>
#include<queue>
#include<set>
#include<cmath>
#define rep(i,l,r) for (int i=l;i<=r;i++)
#define down(i,l,r) for (int i=l;i>=r;i--)
#define clr(x,y) memset(x,y,sizeof(x))
#define maxn 209000
#define inf int(1e9)
#define mm 1000000007
#define esp 1e-6
using namespace std;
#define ll long long
ll f[33][33][2029],c[33][33],cnt[2029];
int n,m,k,l1,l2,tmp;
int read(){
    int x=0,f=1; char ch=getchar();
    while (!isdigit(ch)) {if (ch=='-') f=-1; ch=getchar();}
    while (isdigit(ch)) x=x*10+ch-'0',ch=getchar();
    return x*f;
}
 
int main(){
    n=read(); m=read(); k=read();
    rep(i,1,1<<(k+1)) cnt[i]=cnt[i/2]+(i&1);
    c[0][0]=1;
    rep(i,1,30) {
        c[i][0]=1;
        rep(j,1,i) c[i][j]=(c[i-1][j]+c[i-1][j-1])%mm;
    }
    f[1][0][0]=1;
    rep(i,1,n-1) {
        l1=min(k,n-i+1);
        l2=min(k,n-i);
        rep(s1,0,(1<<l1)-1){
            rep(s2,0,(1<<l2)-1){
                if ((s1&1)==(cnt[(s1>>1)^s2]&1)) {
                    tmp=0;
                    for (int del=cnt[(s1>>1)^s2];del<=m;del+=2,tmp++)
                        for (int j=0;j+del<=m;j++)
                            f[i+1][j+del][s2]=(f[i+1][j+del][s2]+f[i][j][s1]*c[tmp+l2-1][tmp]%mm)%mm;
                }
            }
        }
    }
    printf("%lld\n",f[n][m][0]);
    return 0;
}

posted on 2015-11-22 14:57  ctlchild  阅读(208)  评论(0编辑  收藏  举报

导航