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