 /**//*
题意:给出一个环形链,只有两种字符C,J
现要统计有多少个位置,使得在该位置断开,向左或向右收集字符,收集过程中,C的个数>=J

令第i与i+1个字符之间的间隙为第i个位置,总共可以断开n个位置,而每断开一个位置,可向右或向左
所以用f[i]表示位置i处可行(向左或向右可行即可)

这里只考虑向左的
令 num[i] = str[i]=='C'?1:-1
某个位置i可行,必须有 sum(j i] >=0 即 sum[i] - sum[j] >=0 (i-n<=j<i)
也即只需检查 sum[i]-max{sum[j]}>=0
快速取得一个区间的最大值,用单调队列!
*/
#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;

const int MAXN = 1000010;

char str[MAXN];
int sum[MAXN*2],num[MAXN*2];
int DQ[MAXN];
bool f[MAXN];

int main()
  {
//freopen("in","r",stdin);
int T,n,t=1;
for(scanf("%d",&T);T--;)
 {
scanf("%s",str+1);
n = 0;
for(int i=1;str[i];i++,n++)
num[i] = num[i] = (str[i]=='C'?1:-1);//很方便处理
for(int i=1;i<=n;i++)num[i+n] = num[i];
fill(f+1,f+1+n,false);

int front = 0,tail = 0;
//left to right
//maintain a decreasing sequence
sum[0] = 0;
for(int i=1;i<=n;i++)
 {
sum[i] = sum[i-1] + num[i];
while(front<tail && sum[DQ[tail-1]] <= sum[i] )tail--;
DQ[tail++] = i;
}
for(int i=n+1;i<=n+n;i++)
 {
sum[i] = sum[i-1] + num[i];
while(front<tail && DQ[front]< i-n )front++;
if(sum[i]-sum[DQ[front]]>=0)
 {
f[i-n] = true;
}
while(front<tail && sum[DQ[tail-1]] <= sum[i] )tail--;
DQ[tail++] = i;
}

//right to left
//maintain a decreasing sequence
front = tail = 0;
sum[n+n+1] = 0;
for(int i=n+n;i>=n;i--)
 {
sum[i] = sum[i+1] + num[i];
while(front<tail && sum[DQ[tail-1]] <= sum[i] )tail--;
DQ[tail++] = i;
}
for(int i=n;i>=1;i--)
 {
sum[i] = sum[i+1] + num[i];
while(front<tail && DQ[front]> i+n )front++;
if(sum[i]-sum[DQ[front]]>=0)
 {
if(i-1)f[i-1] = true;
else f[n] = true;
}
while(front<tail && sum[DQ[tail-1]] <= sum[i] )tail--;
DQ[tail++] = i;
}
int ans = 0;
for(int i=1;i<=n;i++)ans += f[i];
printf("Case %d: %d\n",t++,ans);
}
return 0;
}


|
|
常用链接
随笔分类
Links
搜索
最新评论

|
|