洛谷P3594 [POI2015]WIL-Wilcze doły
阿新 • • 發佈:2020-12-12
題面
分析
一道較為簡單的單調佇列題目
思路和上一道題很像,就是列舉右端點,然後找到滿足條件的“最左”的左端點
怎麼找呢,我們發現隨著右端點的右移,其實左端點也在不斷地右移,那麼就是左端點單調不減
然後我們就可以想到單調佇列來維護了
隊列當中維護的資訊是什麼呢...
左端點位置?不是。
因為這樣維護的話我們每次還要在當前區間當中找到最大的長度為\(d\)的區間,很麻煩
所以我們直接維護這個長度為\(d\)的區間的和的最大值,以及這個區間的左端點即可(就是說佇列裡存的是這個區間和的最大值對應區間的位置,而且在這個過程中,我們順帶記一下左端點\(st\)的位置)
然後總複雜度就是\(O(n)\)
程式碼
#include<bits/stdc++.h> using namespace std; template <typename T> inline void read(T &x){ x=0;char ch=getchar();bool f=false; while(!isdigit(ch)){if(ch=='-'){f=true;}ch=getchar();} while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} x=f?-x:x; return ; } template <typename T> inline void write(T x){ if(x<0) putchar('-'),x=-x; if(x>9) write(x/10); putchar(x%10^48); return ; } #define ll long long const int N=2e6+5; ll n,p,d,hh,tt=-1,que[N],a[N],pre[N],val[N],st=1,ans; int main(){ read(n),read(p),read(d); for(int i=1;i<=n;i++) read(a[i]); for(int i=1;i<=n;i++) pre[i]=pre[i-1]+a[i]; for(int i=d;i<=n;i++) val[i]=pre[i]-pre[i-d]; que[++tt]=d,ans=d; for(int i=d+1;i<=n;i++){ while(hh<=tt&&val[i]>val[que[tt]]) tt--;//維護最大的長度為$d$的區間 que[++tt]=i; while(hh<=tt&&pre[i]-pre[st-1]-val[que[hh]]>p) st++; while(hh<=tt&&que[hh]-d+1<st) hh++;//如果本身這個最大值已經不在當前$st-i$的區間內,直接彈出 ans=max(ans,i-st+1); } write(ans); return 0; }