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 $ .
一个很久的题目了,最近在补之前的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
*/