【BZOJ2217】[Poi2011]Lollipop 亂搞
阿新 • • 發佈:2017-12-03
getch 記錄 spa style using 子序列 ++ brush highlight
TWTWT
5
1
7
2 2
NIE
【BZOJ2217】[Poi2011]Lollipop
Description
有一個長度為n的序列a1,a2,...,an。其中ai要麽是1("W"),要麽是2("T")。
現在有m個詢問,每個詢問是詢問有沒有一個連續的子序列,滿足其和為q。
Input
第一行n,m (1<=n,m<=1000000)
第二行這個序列,起始編號為1,終止編號為n
下面每行一個詢問q,詢問有沒有一個連續的子序列,滿足其和為q (1<=q<=2000000)
Output
對於每個詢問,輸出一行,如果有,輸出這個序列的起點和終點(如果有多個輸出任意一個);如果沒有,輸出“NIE”。
Sample Input
5 3TWTWT
5
1
7
Sample Output
1 32 2
NIE
題解:非常奇怪的題。如果存在一個子串的和為x,那麽一定有一個前綴的和為x或x+1(顯然),如果存在一個前綴為x就已經做完了,那麽我們考慮如何由一個前綴x+1得到一個子串x。
我們用類似於雙指針的過程,維護指針l和r不斷向右平移,如果l或r中有一個是1,那麽我們將這個1扔掉就從x+1得到了x,否則l和r都是2,那麽我們將整個區間整體向右平移一格,直到出現1為止。換句話說,我們可以記錄對於每個位置,它後面最長的連續的2有多少個,然後將l和r整體平移那麽多格。如果平移到序列末端還不行,則輸出無解。
#include <cstdio> #include <cstring> #include <iostream> using namespace std; const int maxn=1000010; int n,m,sum; int v[maxn],st[maxn<<1],l[maxn]; char str[maxn]; inline int rd() { int ret=0,f=1; char gc=getchar(); while(gc<‘0‘||gc>‘9‘) {if(gc==‘-‘) f=-f; gc=getchar();} while(gc>=‘0‘&&gc<=‘9‘) ret=ret*10+(gc^‘0‘),gc=getchar(); return ret*f; } int main() { n=rd(),m=rd(); scanf("%s",str); int i,x,a,b; for(i=1;i<=n;i++) v[i]=(str[i-1]==‘T‘)+1,st[sum+=v[i]]=i; for(l[n+1]=1,i=n;i>=1;i--) l[i]=(v[i]==1)?0:l[i+1]+1; for(i=1;i<=m;i++) { x=rd(); if(st[x]) printf("%d %d\n",1,st[x]); else { if(!st[x+1]) puts("NIE"); else { a=1+min(l[1],l[st[x+1]]),b=st[x+1]+a-1; if(b>n) puts("NIE"); else if(v[b]==1) printf("%d %d\n",a,b); else printf("%d %d\n",a+1,b); } } } return 0; }//5 9 TWTWT 1 2 3 4 5 6 7 8 9
【BZOJ2217】[Poi2011]Lollipop 亂搞