模型总结
决策单调性优化dp 采用整体二分 的策略确定每个点的最优决策点
关键点
整体二分的策略 注意复杂度分析,考试不会时可进行尝试
#include <iostream>
#include <cstdio>
#include <cstring>
#define ll long long
using namespace std;
const int inf= 1e9 ;
int read ( ) {
int x= 0 , f= 1 ;
char ch= getchar ( ) ;
while ( ch< '0' || ch> '9' ) {
if ( ch== '-' ) f= - 1 ;
ch= getchar ( ) ;
}
while ( ch>= '0' && ch<= '9' ) {
x= x* 10 + ch- '0' ;
ch= getchar ( ) ;
}
return f* x;
}
const int maxn= 4e4 + 5 ;
int n, k, a[ maxn] ;
ll f[ maxn] , g[ maxn] ;
int tree[ maxn] ;
void add ( int x, int v) {
for ( ; x<= n; x+ = ( x& - x) ) tree[ x] + = v;
}
int qry ( int x) {
int ans= 0 ;
for ( ; x; x- = ( x& - x) ) ans+ = tree[ x] ;
return ans;
}
void solve ( int L, int R, int s, int t) {
int mid= ( s+ t) >> 1 ;
ll tmp= 0 ;
int p= L;
f[ mid] = 1e18 ;
for ( int i= min ( mid- 1 , R) ; i>= L; i-- ) {
tmp+ = qry ( a[ i+ 1 ] ) ;
add ( a[ i+ 1 ] , 1 ) ;
if ( f[ mid] > g[ i] + tmp) {
f[ mid] = g[ i] + tmp; p= i;
}
}
for ( int i= min ( mid- 1 , R) ; i>= L; i-- ) {
add ( a[ i+ 1 ] , - 1 ) ;
}
if ( s<= mid- 1 ) solve ( L, p, s, mid- 1 ) ;
if ( mid+ 1 <= t) solve ( p, R, mid+ 1 , t) ;
}
int main ( ) {
n= read ( ) ; k= read ( ) ;
for ( int i= 1 ; i<= n; i++ ) a[ i] = read ( ) ;
ll ans= 0 ;
for ( int i= 1 ; i<= n; i++ ) {
ans+ = i- 1 - qry ( a[ i] ) ;
add ( a[ i] , 1 ) ;
g[ i] = ans;
}
memset ( tree, 0 , sizeof ( tree) ) ;
for ( int i= 1 ; i< k; i++ ) {
solve ( 1 , n, 1 , n) ;
for ( int j= 1 ; j<= n; j++ ) g[ j] = f[ j] ;
}
printf ( "%d" , g[ n] ) ;
return 0 ;
}