ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Codeforces 1679B. Painting the Array

2022-06-07 13:04:25  阅读:162  来源: 互联网

标签:nxt lst1 int long 1679B using Array Painting define


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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有