bzoj4385 Wilcze doły 單調佇列
阿新 • • 發佈:2019-01-24
(趕腳POI要被許可權。。趕緊趁現在刷幾道水題)。
首先令s[i]表示(1,i)序列的和。現在考慮一段序列(i,j),如何判斷這段序列是否滿足條件呢?當j-i+1<=d時顯然滿足;否則,我們肯定是要讓這一段序列中總和最大的一段(x,x+d)變為0,換句話說,如果設x,使x滿足i<=x,x+d<=j且s[x+d]-s[x]值最大,那麼如果s[i]-s[j-1]-(s[x+d]-s[x])<=p,那麼(i,j)滿足條件。
因此我們列舉右端點j,顯然i隨著j的增大而增大,x也隨之增大。因此我們用單調佇列維護此時(i,j)的x,然後如果s[i]-s[j-1]-(s[x+d]-s[x])>p就不斷i++,第一個滿足條件的i就是當右端點為j時左端點的最大延伸長度。
時間複雜度O(N)。
AC程式碼如下(實現與上述描述有所不同):
#include<iostream> #include<cstdio> #include<cstring> #define ll long long using namespace std; int n,d,q[2000005]; ll s[2000005],p; ll read(){ ll x=0; char ch=getchar(); while (ch<'0' || ch>'9') ch=getchar(); while (ch>='0' && ch<='9'){ x=x*10+ch-'0'; ch=getchar(); } return x; } int main(){ scanf("%d%lld%d",&n,&p,&d); int i; for (i=1; i<=n; i++) s[i]=s[i-1]+read(); int ans=d,head=1,tail=0,j=0; for (i=d; i<=n; i++){ while (head<=tail && s[i]-s[i-d]>s[q[tail]]-s[q[tail]-d]) tail--; q[++tail]=i; while (s[i]-s[j]-s[q[head]]+s[q[head]-d]>p){ j++; if (q[head]-d<j) head++; } ans=max(ans,i-j); } printf("%d\n",ans); return 0; }
by lych
2016.3.3