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单调队列
最新推荐文章于 2021-01-22 19:59:36 发布