HDU 3474 单调队列

点击打开链接

题意:给个成环的字符串,现在要从一个地方断开这个环,然后可以向左或向右走,在走的过程中C的数量要始终保持大于J的数量,问共有多少个这样的端点

思路:没有思路,参考了大神的思路,大神说这是水题,弱哭~~~~,这里解释一下L和R数组的含义应该就可以自己把代码敲出来了,貌似单调队列考的就是这个呢,L数组保存的是从0到i的最小num值,num为前缀和,这里设C为1,J为-1然后求前缀和,R数组是从最后以为到i的最小num值,然后对于判断的条件,这道题写两遍就行了,一次是全都向左走,另一次是全都向右走,写了一个第二个基本完全一样,说一下判断条件,对于当前节点i,它可以的情况是它到右侧的最小值要>=0,即R[i+1]-num[i]>=0,num[i]及它前面的C和J全部去掉了,然后R[i+1]减去它就是后面最小的情况,只有大于等于0才可以继续,然后是后边的那部分加上前边的部分,即num[len]-num[i]+L[i]>=0,后面剩下的和与前边最小的相加,若小于0则说明不可以,反之你懂得,然后另一个方向处理的相同

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int inf=0x3f3f3f3f;
const ll INF=0x3f3f3f3f3f3f3f3fll;
const int maxn=1000010;
char str[maxn];
int L[maxn],R[maxn],num[maxn],vis[maxn];
void init(int len){
    L[1]=num[1];
    for(int i=2;i<=len;i++) L[i]=min(L[i-1],num[i]);
    R[len]=num[len];
    for(int i=len-1;i>=1;i--) R[i]=min(R[i+1],num[i]);
}
int main(){
    int T,cas=1;
    scanf("%d",&T);
    while(T--){
        scanf("%s",str);
        int len=strlen(str);
        memset(vis,0,sizeof(vis));
        num[0]=0;
        for(int i=0;i<len;i++){
            if(str[i]=='C') num[i+1]=num[i]+1;
            else num[i+1]=num[i]-1;
        }
        init(len);
        if(L[len]>=0) vis[0]=1;
        for(int i=1;i<len;i++){
            if(R[i+1]-num[i]>=0&&num[len]-num[i]+L[i]>=0) vis[i]=1;
        }
        num[0]=0;
        int t=0;
        for(int i=len-1;i>=0;i--){
            if(str[i]=='C') num[t+1]=num[t++]+1;
            else num[t+1]=num[t++]-1;
        }
        init(len);
        if(L[len]>=0) vis[0]=1;
        for(int i=1;i<len;i++){
            if(R[i+1]-num[i]>=0&&num[len]-num[i]+L[i]>=0) vis[len-i]=1;
        }
        int ans=0;
        for(int i=0;i<len;i++) if(vis[i]) ans++;
        printf("Case %d: %d\n",cas++,ans);
    }
    return 0;
}

你可能感兴趣的:(数据结构,ACM,HDU,单调队列)