CF1630C Paint the Middle
最简题意
给定一个长度为 \(n\) 的数组,数组中的元素初始值都为零。可以通过以下操作来修改颜色:
- 选择三个元素 \((i,j,k)\) 满足 \(1\leq i<j<k \leq n\),并且保证 \(a_i=a_k\),同时 \(c_i=c_k=0\),那么可以令 \(c_j=1\)。
问题要求找出应用给定操作任意次数后,能够使得 \(\sum_{i=1}^{n}c_i\) 最大的情况。
题意分析
本题的本质是寻找满足条件的三元组,通过反复操作使得尽可能多的 \(c_i\) 被设置为一。可以通过 DP 来解决。设 \(f_i\) 为这个数第一次出现的位置,而 \(dp_i\) 为在处理到第 \(i\) 位时最多能取多少。则当 \(a_i=a_j\) 时 \(dp_i=dp_j+(j-i-1)\)。所以 \(dp_i+i+1=\max{(dp_j+j)}\),维护最大值用线段树就可以做到 \(O(n\log n)\) 的了。
CODE
https://www.luogu.com.cn/paste/yq95w9p4
#include<bits/stdc++.h>
#define wk(x) write(x), putchar(' ')
#define wh(x) write(x), putchar('\n')
#define L (p<<1)
#define R ((p<<1)|1)
#define int long long
#define ull unsigned long long
#define ri register int
#define INF 2147483647
#define mod 998244353
#define N 1000005
#define NO printf("No\n")
#define YES printf("Yes\n")
using namespace std;
int n, m, k, jk, ans, sum, num, cnt, tot;
int dis[N], vis[N], kis[N], f[N];
void read(int &x)
{
x = 0; int ff = 1; char ty;
ty = getchar();
while (!(ty >= '0' && ty <= '9'))
{
if (ty == '-') ff = -1;
ty = getchar();
}
while (ty >= '0' && ty <= '9')
x = (x << 3) + (x << 1) + ty - '0', ty = getchar();
x *= ff; return;
}
void write(int x)
{
if (x == 0)
{
putchar('0');
return;
}
if (x < 0)
{
x = -x;
putchar('-');
}
char asd[201]; int ip = 0;
while (x) asd[++ip] = x % 10 + '0', x /= 10;
for (int i = ip; i >= 1; i--) putchar(asd[i]);
return;
}
// 线段树结构
struct P
{
int l, r, max;
} T[N * 8];
// 更新线段树
void Got(int p, int l, int r, int x, int z)
{
if (l == r)
{
T[p].max = max(T[p].max, z);
return;
}
int mid = (l + r) >> 1;
if (mid >= x) Got(L, l, mid, x, z);
else Got(R, mid + 1, r, x, z);
T[p].max = max(T[L].max, T[R].max);
}
// 查询线段树
int query(int p, int l, int r, int x, int y)
{
if (x <= l && y >= r) return T[p].max;
int mid = (l + r) >> 1, yy = -1e18;
if (mid >= x) yy = max(yy, query(L, l, mid, x, y));
if (mid < y) yy = max(yy, query(R, mid + 1, r, x, y));
return yy;
}
signed main()
{
// 读入
read(n);
for (int i = 1; i <= n; i++) read(dis[i]);
// 初始化
for(int i=1;i<=n;i++) if(!f[dis[i]]) f[dis[i]]=i;
// 初始化线段树
for (int i = 0; i < N; i++) T[i].max = -1e18;
Got(1, 1, n, 1, -1); // 线段树初始化
// 主体部分
for (int i = 2; i <= n; i++)
{
int x = query(1, 1, n, min(f[dis[i]], i - 1), i - 1) - 1;
Got(1, 1, n, i, x); // 更新线段树
// 输出答案
if (i == n) write(x + n);
}
return 0;
}
本文来自博客园,作者:Red_river_hzh,转载请注明原文链接:https://www.cnblogs.com/Red-river-hzh/p/19257059

浙公网安备 33010602011771号