【CF868F】Yet Another Minimization Problem （决策单调性优化dp+分治）

10 篇文章 0 订阅
72 篇文章 2 订阅

code

d p i , j dp_{i,j} ：把前 i i 个数划分 j j 段的最小花费， w i , j w_{i,j} [ i , j ] [i,j] 划分为一段的花费
d p i , j = m i n ( d p [ k ] [ j − 1 ] + w [ k + 1 ] [ i ] ) ， k < i dp_{i,j}=min(dp[k][j-1]+w[k+1][i])，k<i

{ d p ( k 1 , j − 1 ) + w ( k 1 + 1 , i 1 ) ≤ d p ( k 2 , j − 1 ) + w ( k 2 + 1 , i ) d p ( k 2 , j − 1 ) + w ( k 2 + 1 , i 2 ) ≤ d p ( k 1 , j − 1 ) + w ( k 1 + 1 , i ) \left\{ \begin{aligned} dp(k_1,j-1)+w(k_1+1,i_1) \le dp(k_2,j-1)+w(k_2+1,i)\\ dp(k_2,j-1)+w(k_2+1,i_2)\le dp(k_1,j-1)+w(k_1+1,i)\\ \end{aligned} \right.

{ d p ( k 1 , j − 1 ) + w ( k 1 + 1 , i 1 ) ≤ d p ( k 2 , j − 1 ) + w ( k 2 + 1 , i ) d p ( k 2 , j − 1 ) + w ( k 2 + 1 , i 2 ) < d p ( k 1 , j − 1 ) + w ( k 1 + 1 , i ) \left\{ \begin{aligned} dp(k_1,j-1)+w(k_1+1,i_1) \le dp(k_2,j-1)+w(k_2+1,i)\\ dp(k_2,j-1)+w(k_2+1,i_2)< dp(k_1,j-1)+w(k_1+1,i)\\ \end{aligned} \right.

{ w ( k 1 + 1 , i 1 ) − w ( k 2 + 1 , i 1 ) ≤ d p ( k 2 , j − 1 ) − d p ( k 1 , j − 1 ) d p ( k 2 , j − 1 ) − d p ( k 1 , j − 1 ) < w ( k 1 + 1 , i 2 ) − w ( k 2 + 1 , i 2 ) \left\{ \begin{aligned} w(k_1+1,i_1)-w(k_2+1,i_1) \le dp(k_2,j-1)-dp(k_1,j-1)\\ dp(k_2,j-1)-dp(k_1,j-1)< w(k_1+1,i_2)-w(k_2+1,i_2)\\ \end{aligned} \right.

w ( k 1 + 1 , i 1 ) − w ( k 2 + 1 , i 1 ) < w ( k 1 + 1 , i 2 ) − w ( k 2 + 1 , i 2 ) w(k_1+1,i_1)-w(k_2+1,i_1)< w(k_1+1,i_2)-w(k_2+1,i_2)

w ( k 2 + 1 , i 1 ) − w ( k 1 + 1 , i 1 ) > w ( k 2 + 1 , i 2 ) − w ( k 1 + 1 , i 2 ) w(k_2+1,i_1)-w(k_1+1,i_1)> w(k_2+1,i_2)-w(k_1+1,i_2)

#include <cstdio>
#include <cstring>
#define inf 1e18
#define maxn 100005
#define int long long
int n, K, k, curl = 1, curr, cost;
int a[maxn], cnt[maxn];
int dp[maxn][25];

void Delete( int x ) {
cost = cost - cnt[a[x]] + 1;
cnt[a[x]] --;
}

void Add( int x ) {
cost = cost + cnt[a[x]];
cnt[a[x]] ++;
}

void calc( int l, int r ) {
while( curl < l ) Delete( curl ++ );
while( l < curl ) Add( -- curl );
while( curr < r ) Add( ++ curr );
while( r < curr ) Delete( curr -- );
}

//计算[L,R]区间的dp值 决策点枚举范围为[l,r]
void solve( int L, int R, int l, int r ) {
if( L > R || l > r ) return;
int mid = ( L + R ) >> 1, pos, ans = inf;
for( int i = l;i <= r;i ++ ) {
calc( i + 1, mid );
if( ans > dp[i][k - 1] + cost )
ans = dp[i][k - 1] + cost, pos = i;
}
dp[mid][k] = ans;
solve( L, mid - 1, l, pos );
solve( mid + 1, R, pos, r );
}

signed main() {
memset( dp, 0x7f, sizeof( dp ) );
dp[0][0] = 0;
scanf( "%lld %lld", &n, &K );
for( int i = 1;i <= n;i ++ )
scanf( "%lld", &a[i] );
for( k = 1;k <= K;k ++ ) solve( 1, n, 0, n - 1 );
//决策点i表示[j,i]为一个子段，[i+1,k]为一个子段
//所以决策点范围是[0,n-1]而不是[1,n]
printf( "%lld\n", dp[n][K] );
return 0;
}


• 1
点赞
• 1
收藏
觉得还不错? 一键收藏
• 打赏
• 0
评论
05-22 2998
09-07 420
02-28 43

“相关推荐”对你有帮助么？

• 非常没帮助
• 没帮助
• 一般
• 有帮助
• 非常有帮助

ikrvxt

¥1 ¥2 ¥4 ¥6 ¥10 ¥20

1.余额是钱包充值的虚拟货币，按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载，可以购买VIP、付费专栏及课程。