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;
}


 

 

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