题解CF1077F2 Pictures with Kittens (hard version)

CF1077F2 Pictures with Kittens (hard version)
题解里好像没有和我做法一样的 (指状态不一样),那我就来发一篇,定义状态\(f_{i,j}\)表示当前选了\(i\)个数字,在第\(j\)个数字时的和的最大值
那么很容易可以想出转移方程
\(f_{i,j}=\max\limits_{0\le u<j}\limits^{1\le i \le x,0\le j\le n}f_{i-1,u}+a_j\)

很显然直接\(O(n^3)\)转移是不行的,只能过24个点,别问我为什么知道,那么就可以考虑优化,去掉一维,仔细观察发现似乎可以用单调队列优化第三维,那么就可以用\(O(n^2)\)成功转移了
代码

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N = 5005;
typedef long long ll;

ll f[N][N], a[N];
int q[N];

int main()
{
    for (int i = 0; i < N; i++)
        for (int j = 0; j < N; j++)
            f[i][j] = -1e18;
    int n, k, m;
    scanf("%d%d%d", &n, &k, &m);
    for (int i = 1; i <= n; i++)
        scanf("%lld", &a[i]);
    f[0][0] = 0;//初始状态
    for (int i = 1; i <= m; i++)
    {
        int front = 0, tail = -1;
        for (int j = 0; j <= n; j++)
        {
            if (front <= tail && q[front] < j - k)
                front++;
            if (front <= tail)
                f[i][j] = f[i - 1][q[front]] + a[j];
            while (front <= tail && f[i - 1][j] >= f[i - 1][q[tail]])
                tail--;
            q[++tail] = j;//单调队列优化
            //for (int u = 0; u < j; u++)
            //{
            //    if (j - u <= k)
            //        f[i][j] = max(f[i][j], f[i - 1][u] + a[j]);
            //}暴力转移的代码
        }
    }
    ll ans = -1;
    for (int i = n - k + 1; i <= n; i++)
        ans = max(ans, f[m][i]);
    printf("%lld", ans);
}

这里还可以有一个小优化,就是用滚动数组,实测加上滚动数组过后时间从\(7.5s\to 2.97s\)

posted @ 2021-02-18 21:23  DSHUAIB  阅读(56)  评论(0编辑  收藏  举报