TopCoder SRM 532 Div1 Medium DengklekBuildingRoads
問題
N個の町があり、1番からN番の番号がついている。
そこに双方向に通行可能な道路M本を引く。
道路は、異なる町A,Bについて|A-B|≦Kのときに引くことができる。
また、全ての道路を引き終えた後で、全ての町から出ている道路の数は偶数でなくてはならない。
同じ町のペアに複数本の道路を引くこともできる。
このとき、道路の引き方は何通りあるか、mod 10^9+7で求めよ。
制約条件
N,M≦30
K≦8
方針
動的計画法による。
dp[i][j][mask][k]を、
町i番目を見ていて、j本今までに道路を引いて、
直前のK+1個の町の奇数本道路がつながれている町がmaskであらわされたときの場合の数としたい。
i番目の町からk番目の町へ道路をひいていってテーブルを更新したいので、
この場合の数を漏れなく重複なく数えるために、kを0からKまで更新してやることにする。
これで通るのだけれど上手く日本語で説明できない。
ソースコード
const int mod = (int)1e9 + 7; int dp[31][31][1<<9][9]; struct DengklekBuildingRoads{ int numWays(int N, int M, int K){ dp[0][0][0][0]=1; for(int i=1;i<N;i++){ rep(j,M+1)rep(mask,1<<K+1)if((mask&1)==0) (dp[i][j][mask>>1][0]+=dp[i-1][j][mask][min(i-1,K)])%=mod; rep(l,min(K,i))rep(j,M+1)rep(mask,1<<K+1)for(int r=0;r+j<=M;r++) (dp[i][j+r][mask^(r&1)<<K^(r&1)<<K-l-1][l+1]+=dp[i][j][mask][l])%=mod; } return dp[N-1][M][0][min(K,N-1)]; } };