1. 程式人生 > 其它 >daimayuan 875 選元素 (單調佇列優化DP)

daimayuan 875 選元素 (單調佇列優化DP)

  • f[i][l] 表示前i個元素,選l個,且當前位置選的最大值。
  • f[i][l]從f[j][l - 1]轉移, i - k <= j < i,用單調佇列優化
  • 不能有f[i][l] <-- f[i- 1][l] 這樣沒法控制每k個選一個
  • 所以初始還要把f賦-1,f[0][0] = 0
#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(false) ,cin.tie(0), cout.tie(0);
//#pragma GCC optimize(3,"Ofast","inline")
#define ll long long
//#define int long long
const int N = 3e3 + 5;
const int M = 1e5 + 5;
const int INF = 0x3f3f3f3f;
const ll LNF = 0x3f3f3f3f3f3f3f3f;
const ll mod = 998244353;
const double PI = acos(-1.0);
ll a[N], n, k;
ll f[N][N];
int hh[N], tt[N], q[N][N];
ll que( int i, int l) {
 //int de1 = hh[l], de2 = tt[l];
 while( hh[l] <= tt[l] && f[q[tt[l]][l]][l] <= f[i][l] ) -- tt[l];
 //de1 = hh[l], de2 = tt[l];
 q[++tt[l]][l] = i;
 //de1 = hh[l], de2 = tt[l];
 while( hh[l] <= tt[l] && q[hh[l]][l] < i + 1 - k ) ++ hh[l];
 //de1 = hh[l], de2 = tt[l];
 return f[q[hh[l]][l]][l];
}
int main () {
 IOS
 memset ( tt, -1, sizeof tt );
 memset ( f, -1, sizeof f );
 int x; cin >> n >> k >> x;
 // if( x < n / k ) {
 //   cout << -1 << '\n'; return 0;
 // }
 f[0][0] = 0;
 for ( int i = 1; i <= n; ++ i ) cin >> a[i];
 for ( int i = 1; i <= n; ++ i ) {
   for ( int l = 1; l <= min(x, i); ++ l ) {
     ll de = que(i - 1, l - 1);
     ll tmp = de >= 0 ? de + a[i] : -1;
     f[i][l] = tmp;
   }
 }
 ll ans = -1;
 for ( int i = n - k + 1; i <= n; ++ i ) {
    ans = max( ans, f[i][x]);
 }
 cout << ans  << '\n';
 return 0;
}