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;
    }
    
    
posted @ 2020-09-10 20:32  tryatry  阅读(166)  评论(0编辑  收藏  举报