题目链接:点击打开链接
1961: 取硬币
Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 46 Solved: 6
Submit Status Web Board
Description
n个硬币排成一排,你可以取走其中连续的一段硬币,但必须要求这段硬币中正面朝上的个数等于反面朝上的个数,那么你最多可以取走多少枚硬币?
Input
多组实例测试,每组输入一个01字符串(长度小于1000000),其中0表示反面朝上,1表示正面朝上
Output
对于每组数据,输出能取走的最多硬币数量
Sample Input
10110
Sample Output
Case #1: 4
思路:
令temp为当前1的个数与0的个数的差(可以为负,例如1的个数为5,0的个数为8,那么差就为-3),
那么只需要从左到右遍历一遍字符串,不停更新temp值即可,只要这个temp值之前出现过,就说明中间这一段0和1的个数一定相等
比如str[] = "110101111":
我们设i=xi表示当前遍历到第xi个字符
xi=1时,a=1,b=0,temp=1
xi=2时, a=2,b=0,temp=2
xi=3时, a=2,b=1,temp=1(和x1=1时相等,那么找到一个01相等串,长度为2)
xi=4时, a=3,b=1,temp=2(和x1=2时相等,那么又找到一个01相等串,长度也为2)
xi=5时, a=3,b=2,temp=1(和x1=1时相等,找到一个01相等串,长度为4!更优)
.......
xi=7, a=5,b=2,temp=3
xi=8, a=6,b=2,temp=4 ……
综上,答案为4!
PS:用一个数组p[2000005]来存temp的值,因为temp可以为负,所以我们将temp总体+1000000,,p[temp]=5表示temp值最早出现在下标为5的地方
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int MAXN=1e6+10;
char str[MAXN];
int pos[2*MAXN]; // pos[i]=j :记录第一次出现 0 与 1 差值为 i的位置为 j
int main()
{
int text=0;
while(~scanf("%s",str+1))
{
// printf("%d--\n",strlen(str+1));
memset(pos,0,sizeof(pos));
int cnt0=0,cnt1=0,ans=0;
for(int i=1;str[i];i++)
{
if(str[i]=='0')
cnt0++;
else
cnt1++;
int k=cnt0-cnt1+MAXN;
if(pos[k]||cnt0==cnt1)
{
ans=max(ans,i-pos[k]);
}
else
pos[k]=i;
}
printf("Case #%d: %d\n",++text,ans);
}
return 0;
}