题解 -
CF1257E The Contest
题目意思
- CF1257E The Contest
- 给你三个序列
a,b,c,保证
a+b+c是个排列。问你能否通过把一个序列的数字移到另一个序列当中(花费为
1)使得
a为组成排列的前缀,
c为后缀(
a,b,c可以为空)。问构成合法
a,b,c的最小花费。
-
∣a∣+∣b∣+∣c∣≤2e5
Sol
- 考虑如何去构造:
- 我们枚举
a序列结束位置为
l(0≤l≤∣a∣),在枚举
c的起始位置为
r(l≤r≤n+1)
- 我们再设
all=∣a∣+∣b∣+∣c∣,
sa表示第一个人前
all个数中拥有的个数,
sb,sc同理,这个我们可以
O(n)预处理出来。
- 对于每次枚举的
l,r我们总花费为
sbl+scl+(sar−sal)+(scr−scl)+(saall−sar)+(sball−sbr)
- 化简可得:
mi=sbl−sal+scr−sbr+saall+sball
- 那么可以大力发现对于每一个
l,要使
scr−sbr最小。那么我们设一个
mil表示
l≤r≤n 时候
scr−sbr的最小值。
O(n)做一遍即可
Code
#include <bits/stdc++.h>
#define pb push_back
using namespace std;
inline int read()
{
int sum=0,ff=1; char ch=getchar();
while(!isdigit(ch))
{
if(ch=='-') ff=-1;
ch=getchar();
}
while(isdigit(ch))
sum=sum*10+(ch^48),ch=getchar();
return sum*ff;
}
const int N=2e5+5;
int n,m,d,a[N],b[N],c[N],ans;
int ca[N],cb[N],cc[N],mi[N];
int main()
{
n=read();
m=read();
d=read();
int all=n+m+d;
for ( int i=1;i<=n;i++ )
{
a[i]=read();
ca[a[i]]++;
}
for ( int i=1;i<=m;i++ )
{
b[i]=read();
cb[b[i]]++;
}
for ( int i=1;i<=d;i++ )
{
c[i]=read();
cc[c[i]]++;
}
for ( int i=1;i<=all;i++ )
{
ca[i]+=ca[i-1];
cb[i]+=cb[i-1];
cc[i]+=cc[i-1];
}
for ( int i=0;i<=all;i++ )
mi[i]=cc[i]-cb[i];
for ( int i=all-1;i>=0;i-- )
mi[i]=min(mi[i+1],mi[i]);
ans=1e9;
for ( int i=0;i<=all;i++ )
ans=min(ans,cb[i]-ca[i]+mi[i]+ca[all]+cb[all]);
printf("%d\n",ans);
return 0;
}