1. 程式人生 > >狀壓[Jxoi2012]奇怪的道路

狀壓[Jxoi2012]奇怪的道路

小宇從歷史書上了解到一個古老的文明。這個文明在各個方面高度發達,交通方面也不例外。考古學家已經知道,這個文明在全盛時期有n座城市,編號為1…n。m條道路連線在這些城市之間,每條道路將兩個城市連線起來,使得兩地的居民可以方便地來往。一對城市之間可能存在多條道路。

據史料記載,這個文明的交通網路滿足兩個奇怪的特徵。首先,這個文明崇拜數字K,所以對於任何一條道路,設它連線的兩個城市分別為u和v,則必定滿足1 <=|u - v| <= K。此外,任何一個城市都與恰好偶數條道路相連(0也被認為是偶數)。不過,由於時間過於久遠,具體的交通網路我們已經無法得知了。小宇很好奇這n個城市之間究竟有多少種可能的連線方法,於是她向你求助。

方法數可能很大,你只需要輸出方法數模1000000007後的結果。

觀察到K較小可以狀態壓縮
而且狀態也好定義: F i , j , k

F_{i,j,k} i i 個城市用了 j j 條邊當前 K
+ 1 K+1
條邊奇偶性情況。
但是發現不好補表,因為你要計算字首和關係,考慮刷表法用當前狀態更新後來狀態
但是注意算重問題:
即你要列舉連向哪一條邊,這本質是讓統計有序

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long LL;
LL mod=1000000007;
LL F[32][32][(1<<9)];
int n,m,k;
int main(){
	cin>>n>>m>>k;
	F[1][0][0]=1;
	for(int i=1;i<=n;++i){
		for(int l=max(1,i-k);l<i;++l){
			for(int j=0;j<=m;++j){
				for(int S=0;S<=min((1<<(k+1))-1,(1<<i)-1);++S){
					int T=S^(1<<(i-l))^1;
					F[i][j+1][T]=(F[i][j][S]+F[i][j+1][T])%mod;
				}
			}			
		}
		for(int j=0;j<=m;++j){
			for(int S=0;S<=min((1<<(k+1))-1,(1<<i)-1);++S){
				if(S&(1<<k)){continue;}
				F[i+1][j][(S<<1)%(1<<(k+1))]=(F[i+1][j][(S<<1)%(1<<(k+1))]+F[i][j][S])%mod;
			}
		}
	}
	cout<<F[n][m][0];
	return 0;
}