题解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\)