题解 P11233【[CSP-S 2024] 染色】

题目描述

给定一个长度为 n 的正整数数组 A,其中所有数从左至右排成一排。

你需要将 A 中的每个数染成红色或蓝色之一,然后按如下方式计算最终得分:

C 为长度为 n 的整数数组,对于 A 中的每个数 Ai1in):

  • 如果 Ai 左侧没有与其同色的数,则令 Ci=0
  • 否则,记其左侧与其最靠近的同色数Aj,若 Ai=Aj,则令 Ci=Ai,否则令 Ci=0

你的最终得分为 C 中所有整数的和,即 i=1nCi。你需要最大化最终得分,请求出最终得分的最大值。

对于所有测试数据,保证:1T102n2×1051Ai106

solution

两种颜色是没有区别的。fi,j 表示一种颜色最后一个选的是 i,另一种颜色最后一个选的是 j,要求 j<i。转移枚举 i+1i,j 中的哪一个同色。转移到 fi+1,jfi+1,i 中的一个。仔细考虑也就是

fi,j+[ai=ai+1]ai+1fi+1,j

fi,j+[aj=ai+1]ai+1fi+1,i

i 这一维去掉,第一种转移是全局加(直接维护标记),第二种转移是单点修改(事实上甚至是 push_back,不会影响其它已计算的值),需要支持查询全局最大值和 aj=ai+1fj 的最大值,前者用一个变量维护,后者开一个桶维护。我写的复杂度是 O(T(n+V))

code

#include <bits/stdc++.h>
using namespace std;
#ifdef LOCAL
#define debug(...) fprintf(stderr, ##__VA_ARGS__)
#else
#define debug(...) void(0)
#define endl "\n"
#endif
using LL = long long;
template <class T> T& cmax(T& x, const T& y) { return x = max(x, y); }
template <class T> T& cmin(T& x, const T& y) { return x = min(x, y); }
int n, a[200010];
LL buc[1000010];
int mian() {
  cin >> n;
  for (int i = 1; i <= n; i++) cin >> a[i];
  memset(buc, ~0x3f, sizeof buc);
  LL tag = 0, mx = 0;
  buc[0] = 0;
  for (int i = 2; i <= n; i++) {
    LL val = max(mx, buc[a[i]] + tag + a[i]);
    if (a[i] == a[i - 1]) tag += a[i], mx += a[i];
    cmax(mx, val), cmax(buc[a[i - 1]], val - tag);
  }
  cout << mx << endl;
  return 0;
}
int main() {
#ifndef LOCAL
#ifdef NF
  freopen("color.in", "r", stdin);
  freopen("color.out", "w", stdout);
#endif
  cin.tie(nullptr)->sync_with_stdio(false);
#endif
  int t;
  cin >> t;
  while (t--) mian();
  return 0;
}
posted @   caijianhong  阅读(123)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
点击右上角即可分享
微信分享提示