HDU 3474 单调队列
Posted Dan__ge
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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;
}
以上是关于HDU 3474 单调队列的主要内容,如果未能解决你的问题,请参考以下文章
HDU 6047 Maximum Sequence (贪心+单调队列)