洛谷 模擬城市2.0
一次洛谷月賽的T1,當時因為是信心賽,認為第一題應該不會太難,結果想了很久,直接額放棄正解選擇暴力。。。簡直就是巨坑的五維DP。。。mmd
題目背景
博弈正在機房頹一個叫做《模擬城市2.0》的遊戲。
2048年,經過不懈努力,博弈終於被組織委以重任,成為D市市委書記!
他勤學好問,勵精圖治,很快把D市建設成富強民主文明和諧的美好城市。為了進一步深化發展,他決定在海邊建立一個經濟開發區。
題目描述
已知開發區的建築地塊是一個n×n的矩形,而開發區可以建造三種建築: 商業樓,住宅樓,教學樓。這任何兩座建築可以堆疊,可以緊密相鄰。他需要建造正好a座商業樓,b座住宅樓,c座教學樓。但是,城市建成後要應付檢查,如果安排的太混亂會被批評。不過幸運的是,只有一條公路經過了該開發區的一側,就是說,檢察人員全程只能看到開發區的一面。
因此,他需要使得開發區建成後,從正面看去,只有一種類型的建築。
一共有多少種滿足條件的方案呢? 請輸出方案數,並對10^9+7取模。
註意,對於同一個n,會有多組數據。
輸入輸出格式
輸入格式:
第一行兩個整數n,T
接下來T行,每行三個整數,表示該組數據的a,b,c
輸出格式:
輸出共T行,每行一個整數:表示各數據答案取模10^9+7的結果。
輸入輸出樣例
輸入樣例#1:2 1
1 1 0
輸出樣例#1: 4
輸入樣例#2: 2 1
2 1 0
輸出樣例#2: 8
說明
對於20%的數據,n≤2 a,b,c≤3 T≤5
對於另外10%的數據,n≤3 a,b,c≤4 T≤5
對於另外20%的數據,b=0
對於另外10%的數據,T≤10
對於全部100%的數據,a,b,c,n≤25 T≤5×105
樣例1
樣例2
Solution:
正解DP+組合數。(可能有多種方法,這裏說其中的一種)我們發現,從正面看,橫排放置的方塊會互相影響(因為後面的可能比前面高,狀態太復雜且不好轉移),我們可以考慮縱向放置的方案數。縱列和縱列之間不會相互遮擋,因此方案數很好統計。
所以我們需要處理出縱列合法的方案數。雖然有三種方塊,但我們只是需要一種漏在外面,所以可以把另外兩種先不考慮,把它們合成一個狀態。
處理任意一列合法方案數,可以dfs處理,也可以dp。設f[i][j][k][x][y]表示放置到第 i個格子,高度為 j,已經放置的最高高度為 k,已經用了 x個能看見的方塊,y 個不能看見的方塊的方案數。邊界條件:最高可以放到max(a,b,c),我們發現如果高度超過了所有種類顏色的數量,那麽我們不可能使得這種情況合法。需要註意的是, y的最大值應當是2*max(a,b,c),因為我們把另外兩種方塊整合在一起了。那麽就可以按順序暴力的放置了。每個格子可能有兩種操作,在它上面放一個新的格子,或者把下一個格子放到下一行去。如果下個位置的高度超過了枚舉的最高高度,那麽前面就沒有格子可以遮擋它,它必須放能看見的種類,並更新最高高度。否則說明下個位置的高度不夠高,會被前面已經放置的格子遮擋,那麽放什麽種類就都可以啦。
狀態轉移方程:
放到下一行:
f[i+1][0][k][x][y]+=f[i][k][k][x][y];
放到上面:
if (j==k)
f[i][j+1][k+1][x+1][y]+=f[i][j][k][x][y];
else
f[i][j+1][k][x+1][y]+=f[i][j][k][x][y],
f[i][j+1][k][x][y+1]+=f[i][j][k][x][y];
復雜度O(n5)
為了方便統計,標程的 i計算到了n+1這樣我們就可以處理出,因為i=n的所有情況都統計在了f[n+1][0]中。
這樣我們就可以處理出g[i][j]表示在某一列上,用了i 種能看見的方塊,j 種遮擋住的方塊的方案數。每一行的方案數處理出來了,我們就可以開始真正的dp了。
設dp[i][j][k]表示從左往右(正面)放到第i 列,用了j 種能看見的方塊, k種遮擋的方塊的方案數。dp[i+1][j+x][y+k]+=dp[i][j][k]*g[x][y];
復雜度O(n5)
處理出dp數組之後,實際上我們就得到了答案的一部分。如果只有兩種方塊可供放置,那麽dp數組就是答案了就是我先前說的b=0的部分。
但是我們有三種方塊。考慮讓一種方塊漏出來,那麽另外兩種方塊的位置是可以隨意組合的(因為並不會漏在外面)。所以還需要處理一下組合數。數據範圍很小,可以直接預處理。如果只讓一種(如住宅樓)能看見,那麽方案數已經顯而易見了。
dp[n][a][b+c]*C[c+b][b];
dp表示使得a 漏在外面,b,c遮住的方案數。C 數組是組合數,表示一共有b+c個位置,b、c隨意組合的方案數。
那麽最終答案就呼之欲出了。
代碼:
1 #include<bits/stdc++.h> 2 #define mod 1000000007 3 #define N 27 4 using namespace std; 5 inline int read() 6 { 7 int x=0,f=1;char ch=getchar(); 8 while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();} 9 while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();} 10 return x*f; 11 } 12 int f[N][N][N][N][N<<1],g[N][N<<1],C[N<<1][N<<1],dp[N][N][N<<1]; 13 int ans,a,b,c,n,m,T; 14 inline void add(int &x,int y){x+=y;if (x>=mod) x-=mod;} 15 main() 16 { 17 n=read(),T=read(); 18 m=25; 19 f[0][0][0][0][0]=1; 20 for (int i=0;i<n;i++) 21 for (int j=0;j<=m;j++) 22 for (int k=j;k<=m;k++) 23 for (int x=k;x<=m;x++) 24 for (int y=0;y<=(m<<1);y++) 25 if (f[i][j][k][x][y]) 26 { 27 add(f[i+1][0][k][x][y],f[i][j][k][x][y]); 28 if (j==k) 29 add(f[i][j+1][k+1][x+1][y],f[i][j][k][x][y]); 30 else 31 add(f[i][j+1][k][x+1][y],f[i][j][k][x][y]), 32 add(f[i][j+1][k][x][y+1],f[i][j][k][x][y]); 33 } 34 for (int k=0;k<=m;k++) 35 for (int x=k;x<=m;x++) 36 for (int y=0;y<=(m<<1);y++) 37 add(g[x][y],f[n][0][k][x][y]); 38 C[0][0]=1; 39 for(int i=1;i<=(m<<1);i++) 40 { 41 C[i][0]=1; 42 for(int j=1;j<=i;j++) 43 { 44 C[i][j]=C[i-1][j-1]+C[i-1][j]; 45 if (C[i][j]>=mod) C[i][j]-=mod; 46 } 47 } 48 dp[0][0][0]=1; 49 for (int i=0;i<n;i++) 50 for (int j=0;j<=m;j++) 51 for (int k=0;k<=(m<<1);k++) 52 if (dp[i][j][k]) 53 for(int x=0;j+x<=m;x++) 54 for(int y=0;y+k<=(m<<1);y++) 55 add(dp[i+1][j+x][y+k],(1ll*dp[i][j][k]*g[x][y])%mod); 56 while(T--) 57 { 58 a=read(),b=read(),c=read(); 59 ans=0; 60 add(ans,(1ll*dp[n][a][b+c]*C[b+c][b])%mod); 61 add(ans,(1ll*dp[n][b][c+a]*C[c+a][c])%mod); 62 add(ans,(1ll*dp[n][c][a+b]*C[a+b][a])%mod); 63 printf("%d\n",ans); 64 } 65 }
洛谷 模擬城市2.0