ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

CF868F Yet Another Minimization Problem 题解

2022-09-14 18:30:15  阅读:188  来源: 互联网

标签:res Minimization int 题解 cal MAXN CF868F 代价 dp


CF8658F

题意

一个长度为 \(n\) 的序列,要分为 \(m\) 段,每段代价为段内相同数的对数,求总代价的最小值。

分析

设 \(cal(i,j)\) 表示段 \([i,j]\) 内的相同的数的对数,\(dp_i\) 表示当前最后一段以 \(i\) 为末端的最小总代价,则有转移方程:

\[dp_i=\min\limits_{j=1}^{i-1}\{dp_j+cal(i,j)\} \]

,需要优化。观察代价函数 \(cal\),如图,

可以发现上面蓝线左侧的黑色部分变到下面红色部分,即从包含变为相交,其代价减小的是上面蓝线右侧的黑色部分对左侧的贡献,增加的是下面蓝线右侧的黑色部分对左侧的贡献,容易发现增加的贡献小于减少的贡献。由于求的是最小值,因此发现代价函数满足包含劣于相交,即满足四边形不等式,因此 dp 满足决策单调性。

发现转移只需从上一层转移,因此可以使用分治优化,而代价函数可以用类似莫队的方法快速从相邻的转移,所以就做完了。

核心代码

int n,m,a[MAXN],L=1,R,res,f[MAXN],dp[MAXN],mp[MAXN];
inline void add(int x){res+=!mp[x]++;}
inline void del(int x){res-=!--mp[x];}
int cal(int l,int r){
    while(l>L) del(a[L++]);
    while(r<R) del(a[R--]);
    while(l<L) add(a[--L]);
    while(r>R) add(a[++R]);return res;
}
void solve(int l,int r,int pl,int pr){
    if(l>r) return;
    int p=0,mid=(l+r)>>1;dp[mid]=0;
    for(int i=pl;i<=qmin(pr,mid-1);i++)
        if(dp[mid]<f[i]+cal(i+1,mid)) dp[mid]=f[i]+cal(i+1,mid),p=i;
    solve(l,mid-1,pl,p);solve(mid+1,r,p,pr);
}
signed main(){
    qread(n,m);int i,j;for(i=1;i<=n;i++) qread(a[i]);mp[0]=1;
    for(i=1;i<=n;i++) dp[i]=f[i]=cal(1,i);m--;
    while(m--){
        solve(1,n,0,n-1);
        for(i=1;i<=n;i++) f[i]=dp[i];
    }printf("%lld\n",dp[n]);
    return 0;
}

record

标签:res,Minimization,int,题解,cal,MAXN,CF868F,代价,dp
来源: https://www.cnblogs.com/lxy-2022/p/CF868F-Solution.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有