Codeforces Round 915 (Div. 2) D

Cyclic MEX

题面翻译

对于一个长为 \(n\) 的排列 \(p\),定义其权值为 \(\sum_{i=1}^n \operatorname{mex}_{j=1}^ip_j\),也就是 \(p_1\sim p_i\) 中没有出现过的最小自然数的和。

然后你可以对这个排列进行移位操作,问最大权值。

题目描述

For an array $ a $ , define its cost as $ \sum_{i=1}^{n} \operatorname{mex} ^\dagger ([a_1,a_2,\ldots,a_i]) $ .

You are given a permutation $ ^\ddagger $ $ p $ of the set $ {0,1,2,\ldots,n-1} $ . Find the maximum cost across all cyclic shifts of $ p $ .

$ ^\dagger\operatorname{mex}([b_1,b_2,\ldots,b_m]) $ is the smallest non-negative integer $ x $ such that $ x $ does not occur among $ b_1,b_2,\ldots,b_m $ .

$ ^\ddagger $ A permutation of the set $ {0,1,2,...,n-1} $ is an array consisting of $ n $ distinct integers from $ 0 $ to $ n-1 $ in arbitrary order. For example, $ [1,2,0,4,3] $ is a permutation, but $ [0,1,1] $ is not a permutation ( $ 1 $ appears twice in the array), and $ [0,2,3] $ is also not a permutation ( $ n=3 $ but there is $ 3 $ in the array).

输入格式

Each test consists of multiple test cases. The first line contains a single integer $ t $ ( $ 1 \le t \le 10^5 $ ) — the number of test cases. The description of the test cases follows.

The first line of each test case contains a single integer $ n $ ( $ 1 \le n \le 10^6 $ ) — the length of the permutation $ p $ .

The second line of each test case contain $ n $ distinct integers $ p_1, p_2, \ldots, p_n $ ( $ 0 \le p_i < n $ ) — the elements of the permutation $ p $ .

It is guaranteed that sum of $ n $ over all test cases does not exceed $ 10^6 $ .

输出格式

For each test case, output a single integer — the maximum cost across all cyclic shifts of $ p $ .

样例 #1

样例输入 #1

4
6
5 4 3 2 1 0
3
2 1 0
8
2 3 6 7 0 1 4 5
1
0

样例输出 #1

15
5
31
1

提示

In the first test case, the cyclic shift that yields the maximum cost is $ [2,1,0,5,4,3] $ with cost $ 0+0+3+3+3+6=15 $ .

In the second test case, the cyclic shift that yields the maximum cost is $ [0,2,1] $ with cost $ 1+1+3=5 $ .

洛谷 CF

一个很久的题目了,最近在补之前的DE,所以被我翻出来了。
思路就是统计变化产生的代价,只要尝试去思考每一次循环带来的代价的变化就可以写出来了。

考虑在一个队列里面放上这个数组当前位置提供的价值,然后我们每次循环就是把队首弹出,然后给队尾压入一个n,同时把前所有价值大于之前\(a[1]\)的数字都变成a[1] 。然后这个状态的答案就是队列里面所有数字相加。
感性理解一下,这个把前面大于a[1]的数字都变成\(a[1]\)的操作数量不会太多。
可以尝试构造一个很多的情况,然后就会发现出不来。
假如我们有一个数y更新了后面的x个数字,那能够更新的比x还多的自然是比y小的数字,并且还要在原本的数组里面在y的后面,也就是逆序对的情况。但是其实可以发现,逆序对是会导致数组总体的贡献降低的(感性理解),而贡献越小就意味着我们需要更新的数字越少(因为我们的更新是把打的变小),所以这个其实是矛盾的,也就是很难,甚至是无法构造出一个能够逆序对多并且贡献大的情况,也就很难有更新数量多的情况。

超级超级不严谨的证明,都不能叫证明,只能说是通过一些方式把我为什么会有,或者说我应该怎么才能有这种感觉说出来了。

所以直接暴力就好。

不是暴力哦,这样是错误的,要加一个优化,就是要数字相同压缩为一个位置。这样就很明显没问题了。不然会t的。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
inline ll read() {
	char c=getchar();ll a=0,b=1;
	for(;c<'0'||c>'9';c=getchar())if(c=='-')b=-1;
	for(;c>='0'&&c<='9';c=getchar())a=a*10+c-48;return a*b;
}
ll n,a[1000001],que[3000001][2],tail,head,flag[1000001];
int main()
{
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	ll T=read();
	while(T--)
	{
		n=read();
		for(ll i=1;i<=n;i++)
		{
			a[i]=read();
			flag[i]=0;
		}
		flag[0]=0;ll now=0;
		tail=head=0;
		ll ans=0;
		for(ll i=1;i<=n;i++)
		{
			flag[a[i]]=1;
			while(flag[now]==1)now++;
			que[++tail][0]=now;que[tail][1]=1;
			ans+=now;
		}
		ll Max=ans;
		for(ll i=1;i<=n;i++)
		{
			ans-=que[++head][0];
			if(que[head][1]!=1)
			{
				head--;
				que[head+1][1]--;
			}
			ans+=n;
			int ned=0;
			while(que[tail][0]>a[i]&&tail>head)
			{
				ans-=(que[tail][0]*que[tail][1]-a[i]*que[tail][1]);
//				que[now]=a[i];
				ned+=que[tail][1];
				tail--;
			}
			que[++tail][0]=a[i];
			que[tail][1]=ned;
			que[++tail][0]=n;
			que[tail][1]=1;
			Max=max(Max,ans);
		}
		cout<<Max<<endl;
	}
	return 0;
}
/*
1
8
0 4 6 2 7 3 1 5
*/
posted @ 2024-03-27 13:15  HL_ZZP  阅读(1)  评论(0编辑  收藏  举报