其他分享
首页 > 其他分享> > Codeforces 1679B. Painting the Array

Codeforces 1679B. Painting the Array

作者:互联网

I

传送门
\(\texttt{Difficulty:1900}\)

题目大意:

一个长为 \(n(1\leq n\leq 10^5)\) 的序列 \(a(1\leq a_i\leq n)\) 。现在可以将该序列染色,染色方式由 \(01\) 序列 \(b\) 决定,将所有染成 \(0\) 的数字取出来,按原顺序排列得到序列 \(a^{(0)}\) ,由此也可得到 \(a^{(1)}\) 。定义 \(seg(c)\) 为将序列 \(c\) 中相邻的所有相同元素合并后, \(c\) 的大小,求 \(seg(a^{(0)})+seg(a^{(1)})\) 的最大值。

思路

考虑贪心,想要让答案最大就要让不同的数字尽量分开,我们可以考虑遍历序列 \(a\) ,判断当前位置上的数字 \(a_i\) 应当加入到 \(a^{(0)}\) 还是 \(a^{(1)}\) 。分别记录两个序列当前最后一个数字的位置 \(lst0\) , \(lst1\) 。如果 \(a_i\) 与二者最后一个数字都相同,那么无论如何不会增加答案,将 \(lst0\) ,\(lst1\) 都设为 \(i\) 即可,如果仅与一个不同,那么直接加到对应的序列上并更新 \(lst\) ,同时答案 \(+1\) 。最后如果与两个都不相同, 此时加入不同的序列会有所区别。记 \(nxt_i\) 为序列中在 \(a_i\) 之后下一个值等于 \(a_i\) 的数字的位置。我们比较 \(nxt_{lst0}\) 与 \(nxt_{lst1}\) 。哪个更小我们就将当前的数字加入哪边,之后答案 \(+1\) 即可,这里感性的理解是 \(nxt\) 更小的面临的数字被合并的危险更大,因为下一个相同的数字离得较近,于是这样选择会更优。理性的证明可以参考官方题解。\(nxt\) 可以轻松预处理出来,复杂度 \(O(n)\) 。

代码

#include<bits/stdc++.h>
#include<unordered_map>
#include<unordered_set>
using namespace std;
using LL = long long;
using LD = long double;
using ULL = unsigned long long;
using PII = pair<LL, LL>;
using TP = tuple<int, int, int>;
#define all(x) x.begin(),x.end()
#define pb push_back
//#define int LL
//#define lc p*2
//#define rc p*2+1
#define endl '\n'
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f
#pragma warning(disable : 4996)
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
const double eps = 1e-8;
const LL MOD = 1000000007;
const LL mod = 998244353;
const int maxn = 100010;

int N, A[maxn], nxt[maxn], pos[maxn];

void solve()
{
	int ans = 0;
	for (int i = 1; i <= N; i++)
		pos[i] = inf;
	for (int i = N; i >= 1; i--)
		nxt[i] = pos[A[i]], pos[A[i]] = i;
	nxt[0] = inf;
	int lst0 = 0, lst1 = 0;
	for (int i = 1; i <= N; i++)
	{
		if (A[i] != A[lst0] && A[i] != A[lst1])
		{
			if (nxt[lst0] < nxt[lst1])
				lst0 = i;
			else
				lst1 = i;
			ans++;
		}
		else if (A[i] != A[lst1])
		{
			lst1 = i;
			ans++;
		}
		else if (A[i] != A[lst0])
		{
			lst0 = i;
			ans++;
		}
		else
			lst0 = lst1 = i;
	}
	cout << ans << endl;
}

int main()
{
	IOS;
	cin >> N;
	for (int i = 1; i <= N; i++)
		cin >> A[i];
	solve();

	return 0;
}

II

\(\texttt{Difficulty:2100}\)
与 \(I\) 唯一的区别是此题改为求最小值。

思路

与 \(I\) 几乎没什么区别,贪心策略改为要让数字尽可能合并,于是对上述代码做一些小修改即可。

代码

#include<bits/stdc++.h>
#include<unordered_map>
#include<unordered_set>
using namespace std;
using LL = long long;
using LD = long double;
using ULL = unsigned long long;
using PII = pair<LL, LL>;
using TP = tuple<int, int, int>;
#define all(x) x.begin(),x.end()
#define pb push_back
//#define int LL
//#define lc p*2
//#define rc p*2+1
#define endl '\n'
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f
#pragma warning(disable : 4996)
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
const double eps = 1e-8;
const LL MOD = 1000000007;
const LL mod = 998244353;
const int maxn = 100010;

int N, A[maxn], nxt[maxn], pos[maxn];

void solve()
{
	int ans = 0;
	for (int i = 1; i <= N; i++)
		pos[i] = inf;
	for (int i = N; i >= 1; i--)
		nxt[i] = pos[A[i]], pos[A[i]] = i;
	nxt[0] = inf;
	int lst0 = 0, lst1 = 0;
	for (int i = 1; i <= N; i++)
	{
		if (A[i] != A[lst0] && A[i] != A[lst1])
		{
			if (nxt[lst0] > nxt[lst1])
				lst0 = i;
			else
				lst1 = i;
			ans++;
		}
		else if (A[i] == A[lst1])
			lst1 = i;
		else if (A[i] = A[lst0])
			lst0 = i;
		else
			lst0 = lst1 = i;
	}
	cout << ans << endl;
}

int main()
{
	IOS;
	cin >> N;
	for (int i = 1; i <= N; i++)
		cin >> A[i];
	solve();

	return 0;
}

标签:nxt,lst1,int,long,1679B,using,Array,Painting,define
来源: https://www.cnblogs.com/Prgl/p/16351349.html