1. 程式人生 > >bzoj3195: [Jxoi2012]奇怪的道路(狀壓dp)

bzoj3195: [Jxoi2012]奇怪的道路(狀壓dp)

考古學家 必須 多條 一個 高度 .com log .html 兩種

Description

小宇從歷史書上了解到一個古老的文明。這個文明在各個方面高度發達,交通方面也不例外。考古學家已經知道,這個文明在全盛時期有n座城市,編號為1..n。m條道路連接在這些城市之間,每條道路將兩個城市連接起來,使得兩地的居民可以方便地來往。一對城市之間可能存在多條道路。
據史料記載,這個文明的交通網絡滿足兩個奇怪的特征。首先,這個文明崇拜數字K,所以對於任何一條道路,設它連接的兩個城市分別為u和v,則必定滿足1 <=|u - v| <= K。此外,任何一個城市都與恰好偶數條道路相連(0也被認為是偶數)。不過,由於時間過於久遠,具體的交通網絡我們已經無法得知了。小宇很好奇這n個城市之間究竟有多少種可能的連接方法,於是她向你求助。

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

Input

輸入共一行,為3個整數n,m,K。

Output

輸出1個整數,表示方案數模1000000007後的結果。

Sample Input

【輸入樣例1】
3 4 1
【輸入樣例2】
4 3 3

Sample Output

【輸出樣例1】
3

【輸出樣例2】
4
【數據規模】

HINT

100%的數據滿足1

<= n <= 30, 0 <= m <= 30, 1 <= K <= 8.

【題目說明】

兩種可能的連接方法不同當且僅當存在一對城市,它們間的道路數在兩種方法中不同。


在交通網絡中,有可能存在兩個城市無法互相到達。

我討厭數數題……LadyLex大佬太強啦

因為$k$很小,我們考慮狀壓,而且因為奇偶是一種相反的概念,可以用$01$表示

我們可以用二進制數表示$i$可以轉移到的所有數的奇偶性,但是那樣的話有$2^{16}$種可能,太大了

然後發現我們其實只要考慮一邊的狀態就好了,另一邊的狀態可以在枚舉到後面的時候再考慮

於是我們只要考慮第$i$個點以及前面的$k$個點就好了,然後再加一維表示我們考慮到了前面的第$l$個點

那麽狀態就設為$dp[i][j][u][l]$,表示考慮到第$i$個點,已經連了$j$條邊,前$k$個點連邊的奇偶性為$u$,且前$k$個點已經考慮到第$l$個點

然後我們考慮轉移對於第$i-k+l$個點和第$i-k+l+1$個點,如果我們不再加邊,可以直接轉移,即$dp[i][j][u][l]$可以轉移到$dp[i][j][u][l+1]$

然後如果在還合法的情況下加邊,會同時改變兩個點的奇偶性,也就會轉移到$dp[i][j][u\ xor\ 2^k\ xor\ 2^l][l]$(狀態裏第$0$位代表左邊第$k$個點,第$k$位表示點$i$)

然後考慮不同$i$之間的轉移,如果要轉移的話再也不會考慮到左邊第$k$個點了,那麽左邊第$k$個點的奇偶性必須是偶數才行,即$u\&1==0$

然後對於一個點$i$,它的下一個點的狀態就是$l>>1$,所以直接轉移

然後最後的答案就是$dp[n+1][m][0][0]$

 1 //minamoto
 2 #include<bits/stdc++.h>
 3 #define ll long long
 4 using namespace std;
 5 const int mod=1e9+7;
 6 int n,m,k,bin[20],dp[35][35][(1<<9)+5][11];
 7 int main(){
 8     scanf("%d%d%d",&n,&m,&k);
 9     bin[0]=1;for(int i=1;i<=15;++i) bin[i]=bin[i-1]<<1;
10     dp[2][0][0][0]=1;
11     for(int i=2;i<=n;++i) for(int j=0;j<=m;++j) for(int u=0;u<bin[k+1];++u){
12         for(int l=0;l<k;++l)
13         if(dp[i][j][u][l]){
14             (dp[i][j][u][l+1]+=dp[i][j][u][l])%=mod;
15             if(j<m&&i-k+l>0)
16             (dp[i][j+1][u^bin[k]^bin[l]][l]+=dp[i][j][u][l])%=mod;
17         }
18         if((u&1)==0&&dp[i][j][u][k])
19         dp[i+1][j][u>>1][0]=dp[i][j][u][k];
20     }
21     printf("%d\n",dp[n+1][m][0][0]);
22     return 0;
23 }

bzoj3195: [Jxoi2012]奇怪的道路(狀壓dp)