P11233 [CSP-S 2024] 染色题解

在这里插入图片描述

题目

题目传送门
思路来源:这里

题目描述

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

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

C C C 为长度为 n n n 的整数数组,对于 A A A 中的每个数 A i A_i Ai 1 ≤ i ≤ n 1 \leq i \leq n 1in):

  • 如果 A i A_i Ai 左侧没有与其同色的数,则令 C i = 0 C_i = 0 Ci=0
  • 否则,记其左侧与其最靠近的同色数 A j A_j Aj,若 A i = A j A_i = A_j Ai=Aj,则令 C i = A i C_i = A_i Ci=Ai,否则令 C i = 0 C_i = 0 Ci=0

你的最终得分为 C C C 中所有整数的和,即 ∑ i = 1 n C i \sum \limits_{i=1}^n C_i i=1nCi。你需要最大化最终得分,请求出最终得分的最大值。

输入格式

本题有多组测试数据。

输入的第一行包含一个正整数 T T T,表示数据组数。

接下来包含 T T T 组数据,每组数据的格式如下:

第一行包含一个正整数 n n n,表示数组长度。

第二行包含 n n n 个正整数 A 1 , A 2 , … , A n A_1, A_2, \dots, A_n A1,A2,,An,表示数组 A A A 中的元素。

输出格式

对于每组数据:输出一行包含一个非负整数,表示最终得分的最大可能值。

输入输出样例 #1

输入 #1

3
3
1 2 1
4
1 2 3 4
8
3 5 2 5 1 2 1 4

输出 #1

1
0
8

说明/提示

【样例 1 解释】

对于第一组数据,以下为三种可能的染色方案:

  1. A 1 , A 2 A_1, A_2 A1,A2 染成红色,将 A 3 A_3 A3 染成蓝色( 1 2 1 \red{1}\red{2}\blue{1} 121),其得分计算方式如下:
  • 对于 A 1 A_1 A1,由于其左侧没有红色的数,所以 C 1 = 0 C_1 = 0 C1=0
  • 对于 A 2 A_2 A2,其左侧与其最靠近的红色数为 A 1 A_1 A1。由于 A 1 ≠ A 2 A_1 \neq A_2 A1=A2,所以 C 2 = 0 C_2 = 0 C2=0
  • 对于 A 3 A_3 A3,由于其左侧没有蓝色的数,所以 C 3 = 0 C_3 = 0 C3=0
    该方案最终得分为 C 1 + C 2 + C 3 = 0 C_1 + C_2 + C_3 = 0 C1+C2+C3=0
  1. A 1 , A 2 , A 3 A_1, A_2, A_3 A1,A2,A3 全部染成红色( 121 \red{121} 121),其得分计算方式如下:
  • 对于 A 1 A_1 A1,由于其左侧没有红色的数,所以 C 1 = 0 C_1 = 0 C1=0
  • 对于 A 2 A_2 A2,其左侧与其最靠近的红色数为 A 1 A_1 A1。由于 A 1 ≠ A 2 A_1 \neq A_2 A1=A2,所以 C 2 = 0 C_2 = 0 C2=0
  • 对于 A 3 A_3 A3,其左侧与其最靠近的红色数为 A 2 A_2 A2。由于 A 2 ≠ A 3 A_2 \neq A_3 A2=A3,所以 C 3 = 0 C_3 = 0 C3=0
    该方案最终得分为 C 1 + C 2 + C 3 = 0 C_1 + C_2 + C_3 = 0 C1+C2+C3=0
  1. A 1 , A 3 A_1, A_3 A1,A3 染成红色,将 A 2 A_2 A2 染成蓝色( 1 2 1 \red{1}\blue{2}\red{1} 121),其得分计算方式如下:
  • 对于 A 1 A_1 A1,由于其左侧没有红色的数,所以 C 1 = 0 C_1 = 0 C1=0
  • 对于 A 2 A_2 A2,由于其左侧没有蓝色的数,所以 C 2 = 0 C_2 = 0 C2=0
  • 对于 A 3 A_3 A3,其左侧与其最靠近的红色数为 A 1 A_1 A1。由于 A 1 = A 3 A_1 = A_3 A1=A3,所以 C 3 = A 3 = 1 C_3 = A_3 = 1 C3=A3=1
    该方案最终得分为 C 1 + C 2 + C 3 = 1 C_1 + C_2 + C_3 = 1 C1+C2+C3=1

可以证明,没有染色方案使得最终得分大于 1 1 1

对于第二组数据,可以证明,任何染色方案的最终得分都是 0 0 0

对于第三组数据,一种最优的染色方案为将 A 1 , A 2 , A 4 , A 5 , A 7 A_1, A_2, A_4, A_5, A_7 A1,A2,A4,A5,A7 染为红色,将 A 3 , A 6 , A 8 A_3, A_6, A_8 A3,A6,A8 染为蓝色( 35 2 51 2 1 4 \red{35}\blue{2}\red{51}\blue{2}\red{1}\blue{4} 35251214),其对应 C = [ 0 , 0 , 0 , 5 , 0 , 1 , 2 , 0 ] C = [0, 0, 0, 5, 0, 1, 2, 0] C=[0,0,0,5,0,1,2,0],最终得分为 8 8 8

【样例 2】

见选手目录下的 color/color2.in 与 color/color2.ans。

【数据范围】

对于所有测试数据,保证: 1 ≤ T ≤ 10 1\leq T\leq 10 1T10 2 ≤ n ≤ 2 × 1 0 5 2\leq n\leq 2\times 10^5 2n2×105 1 ≤ A i ≤ 1 0 6 1\leq A_i\leq 10^6 1Ai106

测试点 n n n A i A_i Ai
1 ∼ 4 1\sim 4 14 ≤ 15 \leq 15 15 ≤ 15 \leq 15 15
5 ∼ 7 5\sim 7 57 ≤ 1 0 2 \leq 10^2 102 ≤ 1 0 2 \leq 10^2 102
8 ∼ 10 8\sim 10 810 ≤ 2000 \leq 2000 2000 ≤ 2000 \leq 2000 2000
11 , 12 11,12 11,12 ≤ 2 × 1 0 4 \leq 2\times 10^4 2×104 ≤ 1 0 6 \leq 10^6 106
13 ∼ 15 13\sim 15 1315 ≤ 2 × 1 0 5 \leq 2\times 10^5 2×105 ≤ 10 \leq 10 10
16 ∼ 20 16\sim 20 1620 ≤ 2 × 1 0 5 \leq 2\times 10^5 2×105 ≤ 1 0 6 \leq 10^6 106

解析

我们设 d p i dp_i dpi 表示到 i i i 为止前面数的最大得分, l s t a i lst_{a_i} lstai表示在这个点前面 a i a_i ai 出现的位置, s u m i sum_i sumi 表示到i为止的最大相邻的价值和 ( ( (具体见代码 ) ) )
那么我们可以得到
d p i = m a x ( d p i − 1 , d p l s t a i + a i + s u m i − 1 − s u m l s t a i ) dp_i = max(dp_{i - 1}, dp_{lst _ {a_i}} + a_i + sum_{i - 1} - sum_{lst_{a_i}}) dpi=max(dpi1,dplstai+ai+sumi1sumlstai)
但是,这个是错的
我被卡了半天

  1. 因为如果出现如下图这种情况,我们没有统计
  2. 如果出现相邻的两个相同的 a i a_i ai的话,两个 s u m sum sum相减会出现负数,应该为0
    在这里插入图片描述
    1解释:因为我们直接从lst[4]转移,所以我们没有把两对3加进去,但是事实来说是可以加进去的,所以我们的 d p l s t a i dp_{lst _ {a_i}} dplstai因改为 d p l s t a i + 1 dp_{lst _ {a_i} + 1} dplstai+1
    2解释:一旦出现相邻的话,我们就会加一个负数,在不相邻情况,一直 a i ≠ a i − 1 a_i \neq a_{i-1} ai=ai1,所以 s u m i = s u m i − 1 sum_i = sum_{i-1} sumi=sumi1, 所以我们把 s u m i − 1 sum_{i - 1} sumi1 改为 s u m i sum_{i } sumi, 我们经过验算,发现此时 s u m i − s u m l s t a i sum_{i} - sum_{lst_{a_i}} sumisumlstai正好为 0 0 0

所以最终得到的转移式为: d p i = m a x ( d p i − 1 , d p l s t a i + 1 + a i + s u m i − s u m l s t a i ) dp_i = max(dp_{i - 1}, dp_{lst _ {a_i} + 1} + a_i + sum_{i} - sum_{lst_{a_i}}) dpi=max(dpi1,dplstai+1+ai+sumisumlstai)

所以大功告成, 请见代码

Code

#include <bits/stdc++.h>
#define int long long 

using namespace std;

namespace langfengya
{
	void Main();
}

signed main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	langfengya::Main();
	return 0;
}

namespace langfengya
{
	const int N = 2e5 + 10;
	int f[N];
	int sum[N], a[N];
	int t;
	int n;
	int last[1000010];
	void read()
	{
		cin >> n;
		for (int i = 1; i <= n; i++)
		{
			cin >> a[i];
			sum[i] = sum[i - 1] + a[i] * (a[i] == a[i - 1]);
		}
	}
	void solve()
	{
		cin >> t;
		while (t--)
		{
			read();
			memset(last, 0, sizeof(last));
			for (int i = 1; i <= n; i++) 
			{
				f[i] = f[i - 1];
				if (last[a[i]])
				{
					f[i] = max(f[i], f[ last[a[i]] + 1] + sum[i] - sum[ last[a[i]] + 1 ] + a[i]);
				}
				last[a[i]] = i;
			}
			cout << f[n] << endl;
		}
	}
	void Main()
	{
		solve(); 
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值