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; }
hdu3474單調隊列
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.