1. 程式人生 > 實用技巧 >Codeforces 1077 F2. Pictures with Kittens (hard version) dp

Codeforces 1077 F2. Pictures with Kittens (hard version) dp

題目連結

題解

  • 首先考慮直接$dp$的寫法$dp_{i,j,k}$表示在前$i$個數選擇了$j$個數後末尾連續未選擇的數個數為$k$可取得的最大值,轉移也很簡單。
  • 但這個做法是$O(n^3)$的,觀察一下可以發現$k$這一維可以用單調佇列優化掉,然後複雜度就為$O(n^2)$
  • 檢視程式碼
    #include <bits/stdc++.h>
    using namespace std;
    #define _for(i,a,b) for(int i = (a);i <= (b);++i)
    typedef long long ll;
    const int maxn = 5000+5;
    const int mod = 1e9+7;
    ll qpow(ll a,ll b){ll res = 1;for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
    int que[maxn][maxn];
    int top[maxn],tail[maxn];
    int a[maxn];
    ll dp[maxn][maxn];
    
    int main()
    {
    #ifndef ONLINE_JUDGE
        freopen("simple.in","r",stdin);
        freopen("simple.out","w",stdout);
    #endif
        int n,m,k;
        cin>>n>>m>>k;
        for(int i = 1;i <= n;++i)scanf("%d",&a[i]);
        que[k][0] = 0;
        tail[k] = 1;
        memset(dp,-0x3f,sizeof(dp));
        dp[0][k]=0;
        ll ans = -1;
        for(int i = 1;i <= n;++i){
            for(int j = 0;j < k;++j){
                int &s = top[j+1];
                int &t = tail[j+1];
                while(s!=t&&i-que[j+1][s]>=m+1){
                    s++;
                }
                if(s!=t)
                dp[i][j] = dp[que[j+1][s]][j+1]+a[i];
                int &s2 = top[j],&t2 = tail[j]; 
                while(s2!=t2&&dp[i][j]>=dp[que[j][t2-1]][j]){
                    t2--;
                }
                que[j][t2++] = i;
                if(j==0&&n-i<m){
                    ans = max(ans,dp[i][j]);
                }
                
            }
        }
        cout<<ans<<endl;
        return 0;
    }