1. 程式人生 > >[洛谷P1714]切蛋糕

[洛谷P1714]切蛋糕

return 連續 inline -- 個數 digi tdi logs etc

題目大意:給你n個數,要你求一段長度不超過k的、和最大的連續子序列,問你最大的和是多少。

解題思路:單調隊列+前綴和優化。

可以發現,i到j的和與k到j的和,當j變化時,這兩個和的相對大小關系是不變的。

我們用單調隊列保存與當前第i個位置距離小於k(等於則不能加到)的位置,並讓這個位置加到i的和單調遞減。

這樣就能保證每次從隊頭彈出時,之後的和仍是最大。

求一段連續序列的和就用到前綴和優化。

總時間復雜度$O(n)$。

C++ Code:

#include<cstdio>
#include<cctype>
#define N 500005
int n,k,a[N],sa[N],q[N<<1],h,t;
inline int max(int a,int b){return a<b?b:a;}
inline int readint(){
    char c=getchar();
    bool b=false;
    for(;!isdigit(c);c=getchar())b=c==‘-‘;
    int d=0;
    for(;isdigit(c);c=getchar())
    d=(d<<3)+(d<<1)+(c^‘0‘);
    return b?-d:d;
}
int main(){
    n=readint(),k=readint();
    sa[0]=0;
    for(int i=1;i<=n;++i)sa[i]=sa[i-1]+(a[i]=readint());
    int ans=max(0,a[1]);
    if(k==1){
        for(int i=1;i<=n;++i)ans=max(ans,a[i]);
        printf("%d\n",ans);
        return 0;
    }
    q[1]=h=t=1;
    for(int i=2;i<=n;++i){
        while(q[h]+k<=i)++h;
        while(h<=t&&a[i]>sa[i]-sa[q[t]-1])--t;
        q[++t]=i;
        ans=max(ans,sa[i]-sa[q[h]-1]);
    }
    printf("%d\n",ans);
    return 0;
}

[洛谷P1714]切蛋糕