AtCoder Grand Contest #026 D - Histogram Coloring
Time Limit: 2 sec / Memory Limit: 1024 MB
Score :?11001100?points
Problem Statement
Let us consider a grid of squares with?109109?rows and?NN?columns. Let?(i,j)(i,j)?be the square at the?ii-th column?(1≤i≤N)(1≤i≤N)?from the left and?jj-th row?(1≤j≤109)(1≤j≤109)?from the bottom.
Snuke has cut out some part of the grid so that, for each?i=1,2,...,Ni=1,2,...,N, the bottom-most?hihi?squares are remaining in the?ii-th column from the left. Now, he will paint the remaining squares in red and blue. Find the number of the ways to paint the squares so that the following condition is satisfied:
- Every remaining square is painted either red or blue.
- For all?1≤i≤N?11≤i≤N?1?and?1≤j≤min(hi,hi+1)?11≤j≤min(hi,hi+1)?1, there are exactly two squares painted red and two squares painted blue among the following four squares:?(i,j),(i,j+1),(i+1,j)(i,j),(i,j+1),(i+1,j)?and?(i+1,j+1)(i+1,j+1).
Since the number of ways can be extremely large, print the count modulo?109+7109+7.
Constraints
- 1≤N≤1001≤N≤100
- 1≤hi≤1091≤hi≤109
Input
Input is given from Standard Input in the following format:
NN h1h1 h2h2 ...... hNhNOutput
Print the number of the ways to paint the squares, modulo?109+7109+7.
Sample Input 1?Copy
Copy 9 2 3 5 4 1 2 4 2 1Sample Output 1?Copy
Copy 12800One of the ways to paint the squares is shown below:
### #### # #### ### #########Sample Input 2?Copy
Copy 2 2 2Sample Output 2?Copy
Copy 6There are six ways to paint the squares, as follows:
## ## ## ## ## ## ## ## ## ## ## ##Sample Input 3?Copy
Copy 5 2 1 2 1 2Sample Output 3?Copy
Copy 256Every way to paint the squares satisfies the condition.
Sample Input 4?Copy
Copy 9 27 18 28 18 28 45 90 45 23Sample Output 4?Copy
Copy 844733013Remember to print the number of ways modulo?109+7109+7.
?
按照題目的要求,四個字符組成的正方形區域內兩種顏色要各占一半。
先看一個例子
2
3 3
圖案為
##
##
##
方案有這么幾種(兩種字符代表兩種顏色)
|*#|#*|#*|*#|*#|#*|*#|#*|** |##
|#*|*#|*#|*#|*#|#*|#*|#*|##|**
|*#|#*|*#|#*|*#|#*|#*|*#|** |##
一共十種方案
可以總結的規律是如果一列中的顏色沒有連續相同的,比如第1,2,9,10種方案,那么在第一列確定的情況下,第二列還可以有兩種方案,但是一旦有連續相同的了,比如第k和k+1顏色相同,那么在第二列的k和k+1(如果存在的話)顏色就是已經確定的了,這樣其他位置的顏色也是確定的,所以只有一種方案。如此就可以分開來存儲有連續相同的方案數,和交替顏色(無連續相同)的方案數。
用dp[i][0]存無連續相同的方案數。而dp[i][j]分兩種情況。
由于每一列高度不盡相同,還有考慮各種情況。
對于每一列,求無連續相同顏色的方案,只是局限于其與前一列接觸的部分,不接觸的部分顏色可以隨意設置,至于下一列是否會接觸這一部分再又下一列去選擇。
dp[i][j]呢,對于與前一列有接觸的部分,dp[i][j]存 有連續相同的方案數,假如這一列比前一列高出d個,那么dp[i][j] = dp[i - 1][j] * 2 ^ d,對于高出的部分是很靈活的,不會受前一列的限制,可以隨意變化,至于高出來這一塊的dp[i][j]存無連續相同的方案數(有連續相同的方案 在底部接觸部分已經記錄過)。
由于高度可能很大,所以這里采用離散化,把所有的高度存到一個數組里,這樣每個列對應一個高度的下標。由于一共有不多于100列,所有最多有100個不相同的高度,直接按照高度差來計算相關量即可。
先看c++代碼:
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std;const int MOD = (int)1e9 + 7;int n,m,h[101],hnum[101],dh[101];///h記錄每一列高度 dh記錄離散化后的各不相同的高度 hnum記錄h對應dh中的位置,即第幾高的高度 long long dp[101][101];///記錄第i列第n塊高度往上的方案數int pow_(long long x,int y) {///快速冪求 x的y次方long long ans = 1;if(y > 0) {while(y) {if(y % 2)ans = ans * x % MOD;x = x * x % MOD;y /= 2;}}return ans; }int main() {scanf("%d",&n);for(int i = 1;i <= n;i ++) {scanf("%d",&h[i]);dh[++ m] = h[i];///先把高度存到dh數組 下標從1開始,方便后面dp }sort(dh + 1,dh + m + 1);///dh數組排序m = unique(dh + 1,dh + m + 1) - dh - 1;///dh數組離散化去掉重復的高度 m是不相同的高度數for(int i = 1;i <= n;i ++) {hnum[i] = lower_bound(dh + 1,dh + m + 1,h[i]) - dh;///每一列高度在dh數組中對應的位置 }dp[0][0]=1;///初始化 當第0列有1個無連續相同的方案for(int i = 1;i <= n;i ++) {///對每一列每個高度段進行更新 更新過程為從下往上(dp[i][0] += dp[i - 1][0] * 2 % MOD) %= MOD;///無連續相同方案 加上前i - 1列無連續相同方案數*2 因為可以是與前一列對應位置同色或者異色一共兩種方案for(int j = hnum[i] + 1;j <= hnum[i - 1];j ++)///如果前一列比這一列高,高出的部分也存著接觸部分無連續相同的方案 但是可能會重復加上上一步的方案數所以下面更新高出的部分時會避免(dp[i][0] += dp[i - 1][j] * 2 % MOD) %= MOD;int d = pow_(2,h[i] - h[i - 1]);///比前一列高出部分的涂色方案數,如果比前一列低 d就等于1for(int j = 1;j <= min(hnum[i - 1],hnum[i]);j ++) {dp[i][j] = dp[i - 1][j] * d % MOD;///有連續相同顏色的方案數 已經分析過接觸部分的顏色一定是定下的 所以這一列接觸部分有連續相同部分的方案數由高出部分的變化決定 即 乘上d }for(int j = hnum[i - 1] + 1;j <= hnum[i];j ++) {///更新比前一列高出的部分 j從上一列的高度加1的下標開始if(j > 1)(dp[i][j] = dp[i - 1][0] * (pow_(2,dh[j] - dh[j - 1]) - 1) % MOD * 2 % MOD * pow_(2,h[i] - dh[j]) % MOD) %= MOD;///一般情況 前i - 1列無連續方案 * (第j塊高度變化方案 -1表示去掉無連續相同方案) * 2 * 剩下幾塊高度的變化方案數else (dp[1][1] = dp[0][0] * (pow_(2,dh[1]) - 2) % MOD * pow_(2,h[i] - dh[1]) % MOD) %= MOD;///第一列的第一塊高度 記錄隨意變化方案數 -2表示除去dp[i][0]已經記錄過的無連續相同方案 勿重復記錄 }}long long ans = 0;for(int i = 0;i <= hnum[n];i++)(ans += dp[n][i]) %= MOD;printf("%lld",ans);return 0; } View Code?
### #### # #### ### #########
對于樣例一來說,最初dp[0][0] = 1;dh[] = {0,1,2,3,4,5},hnum[] = {0,2,3,5,4,1,2,4,2,1},然后一列一列來
第一列:dp[1][0] = dp[0][0] * 2 = 2,2個無連續相同方案,然后前一列高度為0,所以第一列比前一列高出兩個高度塊,dp[1][1] = 0,dp[1][2] = 2;
第二列:dp[2][0] = dp[1][0] * 2 = 4,dp[2][1] = dp[1][1] * 2 = 0,dp[2][2] = dp[1][2] * 2 = 4;比前一列高出3 - 2 = 1個高度塊,dp[2][3] = 4;
第三列:dp[3][0] = dp[2][0] * 2 = 8,dp[3][1] = dp[2][1] * 4 = 0,dp[3][2] = dp[2][2] * 4 = 16,dp[3][3] = dp[2][3] * 4 = 16,比前一列高出兩個高度塊,dp[3][4] = dp[2][0] * 2 * 2 = 16,dp[3][5] = 8;
第四列:dp[4][0] = dp[3][0] * 2 + dp[3][5] * 2 = 32,dp[4][1] = 0,dp[4][2] = dp[3][2] = 16,dp[4][3] = 16,dp[4][4] = 16;
第五列:dp[5][0] = dp[4][0] * 2 + dp[4][2] * 2 + dp[4][3] * 2 + dp[4][4] * 2 = 160,dp[5][1] = 0;
第六列:dp[6][0] = dp[5][0] * 2 = 320,dp[6][1] = 0,dp[6][2] = dp[5][0] * 2 = 320;
第七列:dp[7][0] = dp[6][0] * 2 = 640,dp[7][1] = 0,dp[7][2] = dp[6][2] * 4 = 1280,dp[7][3] = dp[6][0] * 2 * 2 = 1280,dp[7][4] = dp[6][0] * 2 = 640;
第八列:dp[8][0] = dp[7][0] * 2 + dp[7][3] * 2 + dp[7][4] * 2 = 5120,dp[8][1] = 0,dp[8][2] = dp[7][2] = 1280;
第九列:dp[9][0] = dp[8][0] * 2 + dp[8][2] * 2 = 12800,dp[9][1] = 0;
答案:12800
轉載于:https://www.cnblogs.com/8023spz/p/9406634.html
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的AtCoder Grand Contest #026 D - Histogram Coloring的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Oracle if else if f
- 下一篇: 如何在Ubuntu下安装 monodev