题意:给个成环的字符串,现在要从一个地方断开这个环,然后可以向左或向右走,在走的过程中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; }
时间: 2024-11-01 20:56:02