牛客网 【每日一题】[SCOI2009]粉刷匠
鏈接:
題目描述
windy有 N 條木板需要被粉刷。 每條木板被分為 M 個格子。 每個格子要被刷成紅色或藍色。
windy每次粉刷,只能選擇一條木板上一段連續的格子,然后涂上一種顏色。 每個格子最多只能被粉刷一次。 如果windy只能粉刷 T
次,他最多能正確粉刷多少格子? 一個格子如果未被粉刷或者被粉刷錯顏色,就算錯誤粉刷。
輸入描述:
輸入文件paint.in第一行包含三個整數,N M T。 接下來有N行,每行一個長度為M的字符串,'0’表示紅色,'1’表示藍色。
輸出描述:
輸出文件paint.out包含一個整數,最多能正確粉刷的格子數。
示例1
輸入
輸出
16題意:
n個木板,有m個格子,能粉刷t次,每次可以粉刷連續的一段,問最多能正確粉刷多少個格子?
題解:
怎么涂才最大化?其實全涂最好,為什么?反正涂錯沒懲罰,涂對就算賺,但是我們只能涂t次,所以就是t行涂滿
dp的做法
有二維dp和四維dp的做法
二維dp
就是一個分組背包求解
預處理每塊木板的最優解
因為木板只有0或1,所以我們將1統計出來,剩下的就是0
可以用到前綴和來統計1的數量
pre[i]表示前i塊中1的數量
dp [ i ] [ j ] 表示前i塊木板粉刷j次最多可以刷的格子數
我們根據題意可以得到轉移方程
pree=pre[r]-pre[l]//表示區間l到r之間1的數量
f [ r] [ j ] = max ( f [ r ] [ j ] [ , f [ l ] [ j-1 ] + max ( pree ,r-l-pree))
怎么理解?
前r塊的木板粉刷j次,是前l塊木板粉刷j-1次,再加上l與r之間的最大數(這個最大數是指1和0哪個出現的次數最多,這樣就粉刷數量多的那個顏色)
代碼略
四維dp
dp [ i ] [ j ] [ k ] [ 1 / 0] 表示前i條第j段涂了k次,涂成紅(0)或藍(1)的最多格子數
如果涂的是當前木板第一段(也就是j=1),就要接著上一個木板轉移:
dp[i][j][k][0]=if(a[i][j]==′0 ′)+max(dp[i?1][m][k?1][0],dp[i?1][m][k?1][1])
第i塊木板的第一段是由當前木板的顏色加上上塊木板的最大值情況
dp[i][j][k][1] = if(a[i][j] == ‘1’)+max(dp[i-1][m][k-1][0],dp[i-1][m][k-1][1])
如果不是當前木板第一段,那就是同塊木板的上一段承接而來
dp[i][j][k][0]=if(a[i][j]== ′0′ ) + max(dp[i][j?1][k][0],dp[i][j?1][k?1][1])
dp[i][j][k][1] = if(a[i][j] == ’ 1 ') + max(dp[i][j-1][k-1][0],dp[i][j-1][k][1])
本段木板顏色直接承接前一段的最大值
答案就是看紅(0)或藍(1)哪個最多
dp[n][m][t][0/1]
看到一個大佬用的滾動數組壓維(秒啊)
滾動數組壓維版代碼
for (int i = 1; i <= n; i++)for (int j = 1; j <= m; j++)for (int k = 1; k <= t; k++){if (j == 1)dp[i & 1][j][k][1] = max(dp[(i - 1) & 1][m][k - 1][0], dp[(i - 1) & 1][m][k - 1][1]) + (a[i][j] == 1 + '0');elsedp[i & 1][j][k][1] = max(dp[i & 1][j - 1][k][1], dp[i & 1][j - 1][k - 1][1 ^ 1]) + (a[i][j] == 1 + '0');if (j == 1)dp[i & 1][j][k][0] = max(dp[(i - 1) & 1][m][k - 1][0], dp[(i - 1) & 1][m][k - 1][1]) + (a[i][j] == 0 + '0');elsedp[i & 1][j][k][0] = max(dp[i & 1][j - 1][k][0], dp[i & 1][j - 1][k - 1][0 ^ 1]) + (a[i][j] == 0 + '0');}總結
以上是生活随笔為你收集整理的牛客网 【每日一题】[SCOI2009]粉刷匠的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 牛牛染颜色
- 下一篇: 极星手机 Polestar Phone