【Codeforces】Codeforces Round #452 (Div. 2) E. Segments Removal | 模拟

110 阅读2分钟

本文已参与「新人创作礼」活动, 一起开启掘金创作之路。

【Codeforces】Codeforces Round #452 (Div. 2) E. Segments Removal | 模拟

题目链接

Problem - 899E - Codeforces

题目

image.png

题目大意

Vasya 有一个长度为 nn 的整数数组 a1,a2,...,ana1,a_2,...,a_n

Vasya 在该数组上执行以下操作:每次操作,他都会找到整个数组里最长的连续相等整数段并将其删除。最长的连续相等整数段是指所有满足 al=al+1=al+2=...=ara_l=a_{l+1}=a_{l+2}=...=a_r 的连续区间 (l,r)(l,r)rl+1r-l+1 最大的那一个。如果有超过一个这样的段,则选择最左边的。

例如,如果 Vasya 的数组为 [13,13,7,7,7,2,2,2][13,13,7,7,7,2,2,2],则在一个操作后,它将变为 [13,13,2,2,2][13,13,2,2,2]

计算 Vasya 将数组变空之前可以执行的操作数量。

思路

容易发现本题无需我们进行任何决策,直接模拟即可。容易想到用双向链表存储数据,输入时遇到连续相邻的数字,可以只保留第一个,并统计数量。

找最长的连续相等整数段容易想到用优先队列进行维护,长度为第一关键字从大到小下,标为第二关键字从小到大。我们先把初始处理好的连续段的长度和下标放进优先队列里,然后只要队列不为空我们就持续操作更新操作次数,堆顶元素出堆后更新链表,如果堆顶元素的左右两边值相等,可以将其合并为一个段。

因为我们对段进行合并后,后者的信息依然在优先队列中,我们可以用一个标记数组进行判断。

代码

#include <iostream>
#include <algorithm>
#include <math.h>
#include <stdio.h>
#include <map>
#include <vector>
#include <queue>
#define nnn printf("No\n")
#define yyy printf("Yes\n")
using namespace std;
using LL=long long;
const int N=500001;
const LL mod=1000000007;
//const LL mod=998244353;
struct asdf{
	int id,cnt;
	bool operator < (const asdf a) const
	{
		if (cnt!=a.cnt) return cnt<a.cnt;
		return id>a.id;
	}
};
priority_queue<asdf> q;
int n,m,k,x,y,z,tot,a[N],b[N];
int pre[N],nxt[N],f[N],cnt[N];
int find(int x)
{
	return x==f[x]?x:f[x]=find(f[x]);
}
LL solve()
{
	scanf("%d",&n);
	for (int i=1;i<=n;++i) f[i]=i,cnt[i]=1;
	for (int i=1;i<=n;++i)
	{
		scanf("%d",&a[i]);
		pre[i]=i-1;
		nxt[i]=i+1;
		if (a[i]==a[i-1])
		{
			f[i]=find(i-1);
			nxt[f[i]]=i+1;
			cnt[f[i]]++;
		}
	}
	for (int i=1;i<=n;++i)
		if (f[i]==i) q.push({i,cnt[i]});
	int l,r,ans=0;
	while (!q.empty())
	{
		asdf t=q.top();
		q.pop();
		if (f[t.id]!=t.id) continue;
		ans++;
		f[t.id]=0;
		if (pre[t.id]>=1&&nxt[t.id]<=n&&a[pre[t.id]]==a[nxt[t.id]])
		{
			nxt[find(pre[t.id])]=nxt[nxt[t.id]];
			cnt[f[pre[t.id]]]+=cnt[nxt[t.id]];
			q.push({f[pre[t.id]],cnt[f[pre[t.id]]]});
			f[nxt[t.id]]=f[pre[t.id]];
		}
		else
		{
			nxt[find(pre[t.id])]=nxt[t.id];
			pre[nxt[t.id]]=f[pre[t.id]]; 
		}
	}
	cout<<ans<<endl;
}
int main()
{
	int T=1;
	while (T--) solve();
	return 0;
}