bzoj 4385 poi 2015 Wilcze doły 單調佇列
阿新 • • 發佈:2018-12-14
10319: Wilcze doły
時間限制: 1 Sec 記憶體限制: 128 MB
提交: 69 解決: 24
[提交] [狀態] [討論版] [命題人:admin]
題目描述
給定一個長度為n的序列,你有一次機會選中一段連續的長度不超過d的區間,將裡面所有數字全部修改為0。
請找到最長的一段連續區間,使得該區間內所有數字之和不超過p。
輸入
第一行包含三個整數n,p,d(1<=d<=n<=2000000,0<=p<=10^16)。
第二行包含n個正整數,依次表示序列中每個數w[i](1<=w[i]<=10^9)。
輸出
包含一行一個正整數,即修改後能找到的最長的符合條件的區間的長度。
樣例輸入
複製樣例資料
9 7 2 3 4 1 9 4 1 7 1 3
樣例輸出
5
提示
將第4個和第5個數修改為0,然後可以選出區間[2,6],總和為4+1+0+0+1=6。
來源/分類
題意讓選出最長的一段連續區間使得該區間內數的和不超過p,條件是可以把一段長度不超過d的連續區間裡的數字全部修改為0
第一眼看到,沒思路,後來想了想因為資料2e6,只能O(n),又因為要維護區間的最大值,所以想到單調佇列
但是因為以前接觸的單調佇列都是確定長度的滑動區間,這個找最長就有點懵,覺得自己思路可能錯了
後來上網搜題解,看到確實是單調佇列,然後發現思路有點問題
單調佇列維護的是d長度的最大區間,所以長度是已知,求最長長度的問題就可以囊括在裡面
假設區間i到j之間是維護的該區間,那麼該區間的和減去區間內d長度的和之後大於p,說明該區間不可行,那麼左端點i+1
說的貌似有點亂,但是思路是單調佇列沒錯的
程式碼:
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn=2e6+100; ll s[maxn]; ll f[maxn]; int in[maxn]; int main(){ int n,d; ll p,a; scanf("%d%lld%d",&n,&p,&d); for(int i=1; i<=n; i++){ scanf("%lld",&a); s[i]=s[i-1]+a; } for(int i=d; i<=n; i++){ f[i]=s[i]-s[i-d]; } int tail=0,head=0; int ans=d,i=0; for(int j=d; j<=n; j++){ while(head<=tail && f[j]>=f[in[tail]]) tail--; in[++tail]=j; while(s[j]-s[i]-f[in[head]]>p){ i++; while(head<=tail && in[head]-d<i) head++; } ans=max(ans,j-i); } printf("%d\n",ans); return 0; }