题解 - CF1257E The Contest

题解 - C F 1257 E   T h e   C o n t e s t \mathrm{CF1257E\ The \ Contest}

题目意思

  • CF1257E The Contest
  • 给你三个序列 a , b , c a,b,c ,保证 a + b + c a+b+c 是个排列。问你能否通过把一个序列的数字移到另一个序列当中(花费为 1 1 )使得 a a 为组成排列的前缀, c c 为后缀( a , b , c a,b,c 可以为空)。问构成合法 a , b , c a,b,c 的最小花费。
  • a + b + c 2 e 5 |a|+|b|+|c|\leq 2e5

S o l \mathrm{Sol}

  • 考虑如何去构造:
  • 我们枚举 a a 序列结束位置为 l ( 0 l a ) l(0\leq l \leq |a|) ,在枚举 c c 的起始位置为 r ( l r n + 1 ) r(l\leq r\leq n+1)
  • 我们再设 a l l = a + b + c all=|a|+|b|+|c| s a sa 表示第一个人前 a l l all 个数中拥有的个数, s b , s c sb,sc 同理,这个我们可以 O ( n ) O(n) 预处理出来。
  • 对于每次枚举的 l , r l,r 我们总花费为 s b l + s c l + ( s a r s a l ) + ( s c r s c l ) + ( s a a l l s a r ) + ( s b a l l s b r ) sb_l+sc_l+(sa_r-sa_l)+(sc_r-sc_l)+(sa_{all}-sa_r)+(sb_{all}-sb_r)
  • 化简可得: m i = s b l s a l + s c r s b r + s a a l l + s b a l l mi=sb_l-sa_l+sc_r-sb_r+sa_{all}+sb_{all}
  • 那么可以大力发现对于每一个 l l ,要使 s c r s b r sc_r-sb_r 最小。那么我们设一个 m i l mi_l 表示 l r n l\leq r \leq n 时候 s c r s b r sc_r-sb_r 的最小值。 O ( n ) O(n) 做一遍即可

C o d e \mathrm{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;
}

猜你喜欢

转载自blog.csdn.net/wangyiyang2/article/details/105361951