T1 [JZOJ1035] 粉刷匠

题目描述

  $windy$ 有 $N$ 条木板需要被粉刷。

  每条木板被分为 $M$ 个格子。

  每个格子要被刷成红色或蓝色。

  $windy$ 每次粉刷,只能选择一条木板上一段连续的格子,然后涂上一种颜色。

  每个格子最多只能被粉刷一次。

  如果 $windy$ 只能粉刷 $T$ 次,他最多能正确粉刷多少格子?

  一个格子如果未被粉刷或者被粉刷错颜色,就算错误粉刷。

数据范围

  $1 \leq N,M \leq 50$,$0 \leq T \leq 2500$

分析

  没错,这就是个DP

  设 $f[i][j]$ 表示前 $i$ 条木板粉刷 $j$ 次最多粉刷正确的格子数,$h[i][j]$ 表示第 $i$ 行粉刷 $j$ 次最多粉刷正确的格子数

  显然 $f[i][j]= \mathop{max}\limits_{0 \leq k \leq m} \{ f[i-1][j-k]+h[i][k] \}$

  然后考虑怎么预处理出 $h$ 数组

  由于直接从 $h[i][j-1]$ 转移到 $h[i][j]$ 是很困难的,所以可以加一维 $k$ 表示刷完第 $i$ 条木板的前 $k$ 个格子

  每新一次粉刷的颜色应为粉刷区间内格子最多的颜色

  于是状态转移方程为 $$h[i][j][k]= \mathop{max}\limits_{j-1 \leq l < k} \{ h[i][j-1][l]+max(b[i][k]-b[i][l],k-l-(b[i][k]-b[i][l])) \}$$

  $b[i][j]$ 表示第 $i$ 行前 $j$ 个格子中要粉刷成蓝色的个数,这个可以在输入的时候处理

  最后在 $f$ 数组的转移时,倒序枚举 $j$ 可以降掉第一维 $i$

  我还预处理了每条木板最多粉刷的次数,然后成了考场上跑的最快的代码

2019-08-09 纪中NOIP模拟B组
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
#define N 55
#define T 2505

int n, m, t;
int f[T], g[N][N], h[N][N][N];
int sum[N], pre[N], blue[N][N];
char s[N];

int main() {
    scanf("%d%d%d", &n, &m, &t);
    for (int i = 1; i <= n; i++) {
        scanf("%s", s + 1);
        for (int j = 1; j <= m; j++) {
            if (s[j] == '0') blue[i][j] = blue[i][j - 1];
            else g[i][j] = 1, blue[i][j] = blue[i][j - 1] + 1;
        }
    }
    for (int i = 1; i <= n; i++) {
        sum[i] = 1;
        for (int j = 2; j <= m; j++)
            if (g[i][j] != g[i][j - 1]) sum[i]++;
        pre[i] = pre[i - 1] + sum[i];
    }
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= sum[i]; j++)
            for (int l = 1; l <= m; l++)
                for (int k = j - 1; k < l; k++)
                    h[i][j][l] = max(h[i][j][l], h[i][j - 1][k] +
                     max(blue[i][l] - blue[i][k], l - k - (blue[i][l] - blue[i][k])));
    for (int i = 1; i <= n; i++)
        for (int j = pre[i]; j; j--)
            for (int k = 1; k <= j && k <= sum[i]; k++)
                f[j] = max(f[j], f[j - k] + h[i][k][m]);
    while (!f[t]) t--;
    printf("%d\n", f[t]);
    
    return 0;
}
View Code

相关文章:

  • 2021-09-27
  • 2022-02-02
  • 2021-12-02
  • 2021-10-31
  • 2021-12-26
  • 2021-06-29
  • 2021-09-18
  • 2021-07-25
猜你喜欢
  • 2022-01-03
  • 2021-06-12
  • 2022-01-23
  • 2021-05-27
  • 2021-08-22
  • 2021-06-20
  • 2022-02-17
相关资源
相似解决方案