题解 - CF1257E The Contest

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

题目意思

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

S o l \mathrm{Sol} Sol

  • 考虑如何去构造:
  • 我们枚举 a a a序列结束位置为 l ( 0 ≤ l ≤ ∣ a ∣ ) l(0\leq l \leq |a|) l(0la),在枚举 c c c的起始位置为 r ( l ≤ r ≤ n + 1 ) r(l\leq r\leq n+1) r(lrn+1)
  • 我们再设 a l l = ∣ a ∣ + ∣ b ∣ + ∣ c ∣ all=|a|+|b|+|c| all=a+b+c s a sa sa表示第一个人前 a l l all all个数中拥有的个数, s b , s c sb,sc sb,sc同理,这个我们可以 O ( n ) O(n) O(n)预处理出来。
  • 对于每次枚举的 l , r 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) sbl+scl+(sarsal)+(scrscl)+(saallsar)+(sballsbr)
  • 化简可得: 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} mi=sblsal+scrsbr+saall+sball
  • 那么可以大力发现对于每一个 l l l,要使 s c r − s b r sc_r-sb_r scrsbr最小。那么我们设一个 m i l mi_l mil表示 l ≤ r ≤ n l\leq r \leq n lrn 时候 s c r − s b r sc_r-sb_r scrsbr的最小值。 O ( n ) O(n) O(n)做一遍即可

C o d e \mathrm{Code} 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;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值