【bzoj 1293】[SCOI2009] 生日禮物 指標維護佇列
阿新 • • 發佈:2019-02-08
把所有的點從小到大排序以後,維護 l 和 r 指標,先讓 r++ 直到滿足題目要求,然後再移動 l 指標 直到不能滿足條件為止,但是每一次保證 l 的端點處沒有相同的顏色(貪心,要使答案最下),然後每一次更新答案就好了。這樣,我們每一次都保證了能夠找到一個滿足題目條件的區間(而且沒有遺漏,因為區間滿足單調性),用這個區間去更新答案(正確性),而 l 和 r 都只是向右端點移動,所以時間為
2n (On)。最後,由於上一次在寫cf比賽的時候我自信的直接在原陣列上處理,結果左右指標越界,wa了幾發,心有餘悸就收寫了一個佇列來維護。
不過其實大同小異,各位大牛應該用不著這麼麻煩。
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define maxn 1000020 using namespace std; int n,k,cnt,ans; int vis[63]; int read(){ char c=getchar();int x=0; for(;c>'9'||c<'0';c=getchar()); for(;c>='0'&&c<='9';c=getchar())x=x*10+c-'0'; return x; } struct node{ int x,id; bool operator<(const node& b)const{return id<b.id;} }nod[maxn]; int q[maxn*2],l=1,r; void solve(){ ans=1e9; int tot=0; for(int i=1;i<=cnt;i++){ if(vis[nod[i].x]==0)tot++; vis[nod[i].x]++; q[++r]=i; while(nod[q[l]].x==nod[q[l+1]].x)vis[nod[q[l]].x]--,l++; while(tot>=k){ ans=min(ans,nod[i].id-nod[q[l]].id); vis[nod[q[l]].x]--; if(vis[nod[q[l]].x]==0)tot--; l++; } } printf("%d",ans); } int main(){ scanf("%d%d",&n,&k); for(int x,y,i=1;i<=k;i++){ x=read(); for(int j=1;j<=x;j++){ y=read(); nod[++cnt].x=i,nod[cnt].id=y; } } sort(nod+1,nod+1+cnt); solve(); return 0; }