ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

AGC045B 01 Unbalanced

2021-04-29 15:36:22  阅读:153  来源: 互联网

标签:01 suc int 位置 AGC045B ge calc mx Unbalanced


有个01序列,其中有些位置不确定。你要确定这些位置,最小化最大的区间0和1出现次数的差的绝对值。

\(n\le 10^6\)


把01分别看成\(\pm 1\)。显然可以前缀和之后转化成最大值减最小值之差。

设\(F(M)\)表示最大值不超过\(M\)时,最小值最大是多少。求出\(Z\)表示最小的可能的最大前缀和,把所有不确定位置都取\(-1\)可得。可以贪心求出\(F(M)\):先一开把所有的不确定位置变成\(-1\),从前往后扫,如果当前位置调成\(1\)后面的最大值依然不超过\(M\),那么就调成\(1\)。最后\(\min_{M\ge Z} M-F(M)\)就是答案。这是\(O(n^2)\)的做法。

可以优化:考虑\(F(M)\)到\(F(M+2)\)的变化。在做\(F(M)\)的过程中,第一次遇到把不确定位置调成\(1\)就会超过\(M\)的位置,在这里做\(F(M+2)\)的过程中能够调成\(1\),然后因为已经给后缀全体加\(2\)所以剩下的和做\(F(M)\)时一样。如果最小值在这个位置后面,就顶多会加\(2\)。因此有\(F(M)+2\ge F(M+2)\),也就是\(F(M)-M\ge F(M+2)-(M+2)\)。

于是只需要算\(F(Z)\),\(F(Z+1)\)。时间\(O(n)\)。


using namespace std;
#include <bits/stdc++.h>
#define N 1000005
char str[N];
int n,a[N],s[N];
int suc[N];
int calc(int lim){
	int c=0,res=0;
	for (int i=1;i<=n;++i){
		if (a[i]==0){
			if (suc[i]+c+2<=lim)
				c+=2;
		}
		res=min(res,s[i]+c);
	}
	return res;
}
int main(){
	freopen("in.txt","r",stdin);
	scanf("%s",str+1);
	n=strlen(str+1);
	for (int i=1;i<=n;++i)
		a[i]=(str[i]=='0'?1:str[i]=='1'?-1:0);
	int mx=0;
	for (int i=1;i<=n;++i)
		s[i]=s[i-1]+(a[i]<=0?-1:1),mx=max(mx,s[i]);
	suc[n]=s[n];
	for (int i=n-1;i>=1;--i)
		suc[i]=max(suc[i+1],s[i]);
	int ans=min(mx-calc(mx),mx+1-calc(mx+1));
	printf("%d\n",ans);
	return 0;
}

标签:01,suc,int,位置,AGC045B,ge,calc,mx,Unbalanced
来源: https://www.cnblogs.com/jz-597/p/14718076.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有