Yet Another Minimization Problem

Yet Another Minimization Problem

一个很显然的决策单调性。

方程是很显然的$f_i = \min\{f_{j-1} + w(j,i)\}$。

它具有决策单调性,可以参考钟神的 Blog

我们考虑怎么实现这个东西,按照上次 DLS 讲的,考虑 solve(l,r,L,R) 表示 我们当前在处理$l,r$的$dp$ 值,我们知道当前决策点在$L,R$内。

然后考虑怎么求,先对$mid$暴力跑出决策位置,然后分治 solve(l,mid-1,L,op),solve(mid+1,r,op,R)。复杂度是$nlogn$的,因为每一层分治的时间是$O(r - l + R - L)$

但是还得求$w(l,r)$,这个东西我们可以直接类似莫队来算,因为总的移动的位置的和就是前面的$R - L$的和,这个是不影响复杂度的。

代码很短,也很好写。。(没开llwa了两发

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include "iostream"
#include "algorithm"
#include "cstring"
#include "cstdio"
using namespace std;
#define MAXN 100006
#define chkmn( a , b ) ( (a) > (b) ? ( (a) = (b) , 1 ) : 0 )
#define chkmx( a , b ) ( (a) < (b) ? ( (a) = (b) , 1 ) : 0 )
#define f( a ) ( (a) > 0 ? (a) : 0 )
int n , k;
int A[MAXN] , cn[MAXN];
int L = 1 , R = 0;
long long cw , dp[MAXN] , nw[MAXN];
void upd(int c,int d){ cw += 1ll * d * cn[c] * (cn[c] - 1) / 2;}
long long getw( int l , int r ) {
while( L < l ) upd( A[L] , -1 ) , -- cn[A[L]] , upd( A[L] , 1 ) , ++ L;
while( R > r ) upd( A[R] , -1 ) , -- cn[A[R]] , upd( A[R] , 1 ) , -- R;
while( L > l ) -- L , upd( A[L] , -1 ) , ++ cn[A[L]] , upd( A[L] , 1 );
while( R < r ) ++ R , upd( A[R] , -1 ) , ++ cn[A[R]] , upd( A[R] , 1 );
return cw;
}
void solve( int l , int r , int L , int R ) {
if( l > r ) return;
int mid = l + r >> 1 , op; nw[mid] = 0x3f3f3f3f3f3f3f3f;
for( int i = min( R , mid ) ; i >= L ; -- i ) {
if( chkmn( nw[mid] , dp[i - 1] + getw( i , mid ) ) ) op = i;
}
if( l == r ) return;
solve( l , mid - 1 , L , op ) , solve( mid + 1 , r , op , R );
}
int main() {
cin >> n >> k;
for( int i = 1 ; i <= n ; ++ i ) scanf("%d",&A[i]);
memset( dp , 0x3f3f , sizeof dp ) , memset( nw , 0x3f3f , sizeof nw ) , dp[0] = 0;
for( int i = 1 ; i <= k ; ++ i ) {
solve( 1 , n , 1 , n );
swap( nw , dp );
}
cout << dp[n] << endl;
}
文章作者: yijan
文章链接: https://yijan.co/old89/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Yijan's Blog