hdu3474单调队列

 http://acm.hdu.edu.cn/showproblem.php?pid=3474

 

题意:给你一个只包含C和J的项链(10^6),问从哪些位置切了之后从改位置往后到每个位置C的个数都不小于J的个数。。。两个方向均可。。。求有多少个位置满足。。

 

 

分析:记得这是去年多校的题。。那时候还不会。。先加倍,从前往后求和sum[i],其实就是要保证对i元素后面的n个元素满足:min(sum[i+1...i+n])-sum[i]>=0

所以转化一下就是维护一个n的区间内的最小值而已。。。很水的单调队列了。。注意向两端求的时候结果对应的位置一定要正确。。。

 

做起来都是浮云。。。迅速从题意分析出模型才是王道。。。

 

 

代码:

#include<iostream>
#include<stdio.h>
using namespace std;

const int N=4000100;
char s[N];
int sum[N], ans[N], q[N];
int n, head, tail;

int main()
{
    int i, j, tmp, cnt, cas1=1, T;
    scanf("%d", &T);
    while(T--)
    {
        scanf("%s", s);
        n = strlen(s);
        for(i=0; i<n; i++)
            s[i+n] = s[i];
        s[2*n] = 0;
        
        for(i=0; i<2*n; i++)
            ans[i] = 0;

        tmp = 0;
        for(i=0; i<2*n; i++)
        {
            if(s[i]=='C')    tmp++;
            else    tmp--;
            sum[i] = tmp;
        }
        head = tail = 0;
        for(i=0; i<n; i++)
        {
            while(head<tail && sum[q[tail-1]]>sum[i])
                tail--;
            q[tail++] = i;
        }
        if(sum[q[head]]>=0)
            ans[0] = 1;
        for(; i<2*n; i++)
        {
            while(head<tail && sum[q[tail-1]]>sum[i])
                tail--;
            q[tail++] = i;
            while(i-q[head]>=n)
                head++;
            if(sum[q[head]]-sum[i-n]>=0)
                ans[i-n+1] = 1;
        }

        tmp = 0;
        for(i=2*n-1; i>=0; i--)
        {
            if(s[i]=='C')    tmp++;
            else    tmp--;
            sum[i] = tmp;
        }
        head = tail = 0;
        for(i=2*n-1; i>=n; i--)
        {
            while(head<tail && sum[q[tail-1]]>sum[i])
                tail--;
            q[tail++] = i;
        }
        if(sum[q[head]]>=0)
            ans[n] = 1;
        for(; i>0; i--)
        {
            while(head<tail && sum[q[tail-1]]>sum[i])
                tail--;
            q[tail++] = i;
            while(q[head]-i>=n)
                head++;
            if(sum[q[head]]-sum[i+n]>=0)
                ans[i] = 1;
        }

        cnt = 0;
        for(i=1; i<n; i++)
            cnt += ans[i];
        if(ans[0]==1 || ans[n]==1)
            cnt++;
        printf("Case %d: %d\n", cas1++, cnt);
    }
    return 0;
}


 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章