Monotonicity 2[POI2010]
題目描述
給出N個正整數a[1..N],再給出K個關系符號(>、<或=)s[1..k]。
選出一個長度為L的子序列(不要求連續),要求這個子序列的第i項和第i+1項的的大小關系為s[(i-1)mod K+1]。
求出L的最大值。
輸入
第一行兩個正整數,分別表示N和K (N, K <= 500,000)。
第二行給出N個正整數,第i個正整數表示a[i] (a[i] <= 10^6)。
第三行給出K個空格隔開關系符號(>、<或=),第i個表示s[i]。
輸出
一個正整數,表示L的最大值。
樣例輸入
7 3 2 4 3 1 3 5 3 < > =
樣例輸出
6
提示
選出的子序列為2 4 3 3 5 3,相鄰大小關系分別是< > = < >。
【題解】
喜聞樂見的數據結構優化dp。看完了題,在演草紙上寫了一句“動規吧?”,然後就把這句話放一邊了。覺得二分應該能行,就寫了個二分。怎麽check呢?寫了個dfs。後來跟wzz說這個事,大佬非常不理解地說:還不如直接深搜呢,白白地加個log。瞬間覺得好有道理啊,果然上午不知道幹了些什麽。
下午聽講題,自己連O(n^2)的轉移方程都沒寫出來,簡直了。正解思路很清奇,f[i]表示到i這一位最長的子序列長度,有了長度符號就定下來了。不等號按符號維護線段樹,等號直接拿數組標記一下。線段樹的下標是a[i]的權值,內容是f[i]的權值,這樣區間查詢滿足不等號的最大值就非常快了。得出f[i]之後推出下一位的符號,更新相應的線段樹或數組即可。
線段樹是個好東西。上次方伯伯的玉米田用到了樹狀數組優化dp,這一次算是第二道數據結構優化dp。雖然在理論上來講樹狀數組比線段樹好打多了,可我始終還是更喜歡線段樹。連續兩天的dp題都是想過它是dp,但還是沒按dp來做。學完一段時間以後dp能力下降得多了,想當初正在講的時候也是不怕想正解的。原來以為自己不擅長數學和數據結構,現在看來dp也不是很行,集訓要做的事還太多了啊。
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int sj=500010; char fh[sj]; int n,k,a[sj],f[sj],dh[1000010],temp,jg,jd; void bj(int &x,int y) { x=x>y?x:y; } struct Tree { int l,r,jz; }ds[1000010*4],xs[1000010*4]; void bt1(int x,int y,int z) { ds[x].l=y; ds[x].r=z; if(y==z) return; int mid=(y+z)>>1; bt1(x<<1,y,mid); bt1((x<<1)|1,mid+1,z); } void bt2(int x,int y,int z) { xs[x].l=y; xs[x].r=z; if(y==z) return; int mid=(y+z)>>1; bt2(x<<1,y,mid); bt2((x<<1)|1,mid+1,z); } int query1(int x,int y,int z) { if(ds[x].l==y&&ds[x].r==z) return ds[x].jz; int mid=(ds[x].l+ds[x].r)>>1; if(mid<y) return query1((x<<1)|1,y,z); if(z<=mid) return query1(x<<1,y,z); return max(query1(x<<1,y,mid),query1((x<<1)|1,mid+1,z)); } int query2(int x,int y,int z) { if(xs[x].l==y&&xs[x].r==z) return xs[x].jz; int mid=(xs[x].l+xs[x].r)>>1; if(mid<y) return query2((x<<1)|1,y,z); if(z<=mid) return query2(x<<1,y,z); return max(query2(x<<1,y,mid),query2((x<<1)|1,mid+1,z)); } void update1(int x,int y,int z) { if(ds[x].l==ds[x].r&&ds[x].r==z) { ds[x].jz=y; return; } int mid=(ds[x].l+ds[x].r)>>1; if(mid<z) update1((x<<1)|1,y,z); if(z<=mid) update1(x<<1,y,z); ds[x].jz=max(ds[x<<1].jz,ds[(x<<1)|1].jz); } void update2(int x,int y,int z) { if(xs[x].l==xs[x].r&&xs[x].r==z) { xs[x].jz=y; return; } int mid=(xs[x].l+xs[x].r)>>1; if(mid<z) update2((x<<1)|1,y,z); if(z<=mid) update2(x<<1,y,z); xs[x].jz=max(xs[x<<1].jz,xs[(x<<1)|1].jz); } int main() { scanf("%d%d",&n,&k); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); bj(jd,a[i]); } for(int i=1;i<=k;i++) cin>>fh[i]; bt1(1,1,jd); bt2(1,1,jd); for(int i=1;i<=n;i++) { if(dh[a[i]]+1>f[i]) f[i]=dh[a[i]]+1; if(a[i]!=jd) { temp=query1(1,a[i]+1,jd); if(temp+1>f[i]) f[i]=temp+1; } if(a[i]!=1) { temp=query2(1,1,a[i]-1); if(temp+1>f[i]) f[i]=temp+1; } temp=f[i]%k; if(!temp) temp=k; if(fh[temp]==‘=‘) dh[a[i]]=f[i]; if(fh[temp]==‘>‘) update1(1,f[i],a[i]); if(fh[temp]==‘<‘) update2(1,f[i],a[i]); bj(jg,f[i]); } printf("%d",jg); return 0; }
Monotonicity 2[POI2010]