CSP-S 2024 T3 染色 题解

一道自认为特别好的 dp 题,虽然水,但是感觉很适合刚学 dp 的人做的一道题。

题目链接:https://www.luogu.com.cn/problem/P11233


考虑 dfs 暴力,枚举每一个位置的颜色,记录当前位置上一个的红色和蓝色的数的值,在中途统计答案。时间复杂度:O(2n)


考虑将 dfs 暴力转化为 dp,将 dfs 中记录的状态转化为 fi,j,k,表示选到第 i 个,从第 i 个数起,从右往左第一个红色数为 j,第一个蓝色数为 k 的最大代价,转移和 dfs 基本一样。时间复杂度:O(n3)


容易发现一个性质,我们没必要将 jk 都记录下来,因为 jk 中一定有一个为 ai,这样又可以把状态设计为 fi,j,0/1 表示选到第 i 个数,第 i 个数的颜色为 0/1(红或蓝),上一个与第 i 个数异色的数为 j 的最大代价。转移方程为:

fi,j,ofi1,j,o+ai[ai=ai1]

fi,ai1,omaxj{fi1,j,¬o+j[j=ai]}

时间复杂度:O(n2)


将第二个转移式拆分为两个:

fi,ai1,omaxjfi1,j,¬o

fi,ai1,ofi1,ai,1+ai

对于这三个转移式,我们首先可以将 i 通过滚动数组滚掉,然后可以维护一个全局 max 和一个全局加的 tag,这样就可以做到 O(n) 的转移了。

时间复杂度:O(n)


代码如下:

#include <bits/stdc++.h>

using namespace std;

const int kMaxN = 1e6 + 5;

int T, n, maxa, a[kMaxN];
long long f[kMaxN][2], ans, g[2], h[2];

int main() {
  ios::sync_with_stdio(0), cin.tie(0);
  for (cin >> T; T; T--, maxa = ans = 0) {
    cin >> n;
    for (int i = 1; i <= n; i++) {
      cin >> a[i], maxa = max(maxa, a[i]);
    }
    for (int i = 0; i <= maxa; i++) {
      f[i][0] = f[i][1] = -1e18;
    }
    f[0][0] = f[0][1] = g[0] = g[1] = h[0] = h[1] = 0;
    for (int i = 1; i <= n; i++) {
      long long tmp[2] = {};
      for (int o = 0; o < 2; o++) {
        tmp[o] = max({f[a[i - 1]][o], g[o ^ 1] - a[i] * (a[i] == a[i - 1]), f[a[i]][o ^ 1] + a[i] - a[i] * (a[i] == a[i - 1])});
      }
      for (int o = 0; o < 2; o++) {
        h[o] += a[i] * (a[i] == a[i - 1]), g[o] = max(g[o], f[a[i - 1]][o] = tmp[o]);
      }
    }
    for (int i = 0; i <= maxa; i++) {
      ans = max(ans, max(f[i][0] + h[0], f[i][1] + h[1]));
    }
    cout << ans << '\n';
  }
  return 0;
}

水题,但是考试上没有细想,以为题目太难,直接开始打 T4 暴力,如果仔细想一下的话,肯定是能够想出来的。

posted @   liruixiong0101  阅读(64)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示