TopCoder SRM 532 Div2 Hard DengklekPaintingSquares
問題
NxMのグリッドがある。
それぞれのマスについて、色を塗るか塗らないか選ぶ。
色を全て塗り終えた後で、
- 色が塗られているマスに(上下左右に)隣接する色の塗られているマスの数はすべて偶数である
ような色の塗り方は何通りあるか、求めよ。
制約条件
N≦100
M≦8
方針
一列分を覚える動的計画法による。
それぞれのマスは、「色が塗られていない」「色が塗られていて、隣接する色のついたマスが偶数個」「色が塗られていて、隣接する色のついたマスが奇数個」の3通りに分けて覚えればよい。
一列分は、これを3進数としてコードして表現する。
これを1マスずつ更新していけばいい。
ソースコード
const int mod=(int)1e9+7; int dp[2][9][20000]; struct DengklekPaintingSquares{ int numSolutions(int N, int M){ int pw[9], cur=0, next=1; pw[0]=1; rep(i,9)pw[i+1]=pw[i]*3; dp[0][M][0]=1; rep(i,N){ memset(dp[next],0,sizeof(dp[next])); rep(j,pw[M])dp[next][0][j]=dp[cur][M][j]; rep(j,M)rep(k,pw[M])if(dp[next][j][k]){ int prev=k/pw[j]%3, left=j?k/pw[j-1]%3:-100; rep(nxt,2){ if(prev==2&&nxt==0||prev==1&&nxt==1)continue; int nk=k+(nxt-prev)*pw[j]; if(nxt&&(prev>0)+(left>0)==1)nk+=pw[j]; if(nxt&&left==1)nk+=pw[j-1]; if(nxt&&left==2)nk-=pw[j-1]; (dp[next][j+1][nk]+=dp[next][j][k])%=mod; } } swap(cur, next); } int ans=0; rep(i,pw[M]){ rep(j,M)if(i/pw[j]%3==2)goto FAIL; (ans+=dp[cur][M][i])%=mod; FAIL:; } return ans; } };