CF868F Yet Another Minimization Problem 解题报告
题意翻译
题目描述:给定一个序列 ,要把它分成 个子段。每个子段的费用是其中相同元素的对数。求所有子段的费用之和的最小值。 输入格式:第一行输入 (序列长度)和 (需分子段数)。接下来一行有 个数,第 个数表示序列的第 个元素 。 输出格式:输出一个数,费用和的最小值。 ,, 。
题目描述
You are given an array of integers . The cost of a subsegment is the number of unordered pairs of distinct indices within the subsegment that contain equal elements. Split the given array into non-intersecting non-empty subsegments so that the sum of their costs is minimum possible. Each element should be present in exactly one subsegment.
输入输出格式
输入格式
The first line contains two integers and ( , — the length of the array and the number of segments you need to split the array into. The next line contains integers ( ) — the elements of the array.
输出格式
Print single integer: the minimum possible total cost of resulting subsegments.
输入输出样例
输入样例 #1
7 3
1 1 3 3 3 2 1
输出样例 #1
1
输入样例 #2
10 2
1 2 1 2 1 2 1 2 1 2
输出样例 #2
8
输入样例 #3
13 3
1 2 2 2 1 2 1 1 1 2 2 1 1
输出样例 #3
9
说明
In the first example it's optimal to split the sequence into the following three subsegments: , , . The costs are , and , thus the answer is . In the second example it's optimal to split the sequence in two equal halves. The cost for each half is . In the third example it's optimal to split the sequence in the following way: , , . The costs are , , .
SOLUTION
首先来一波BF~ 🤢
设表示前个数分成段的最小费用
emmm...很好,,直接寄掉。
于是我们考虑优化
我们可以浅浅发现好像这个dp满足决策单调性
因为的最优决策点肯定小于等于
具体证明:(略)
于是我们就可以通过分治优化dp
接下来的问题就是如何求出了
我们可以借助莫队的思想,挪动l,r端点来达到优化时间的目的
总复杂度
CODE
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e5+2;
ll L=1,R,f[N][23],a[N],cnt[N],n,m,ans,k;
ll w(ll l, ll r){//动态算一下贡献,类似于莫队
while(L<l) ans-=(--cnt[a[L++]]);
while(R>r) ans-=(--cnt[a[R--]]);
while(L>l) ans+=cnt[a[--L]]++;
while(R<r) ans+=cnt[a[++R]]++;
return ans;
}
void solve(ll l,ll r,ll L,ll R){//分治
if(l>r) return;
ll p=0,mid=(l+r)>>1;
for(ll i=L; i<=min(R,mid-1); i++){//p:最优决策点
if(f[i][k-1]+w(i+1,mid)<f[mid][k]) f[mid][k]=f[p=i][k-1]+w(i+1,mid);
}
solve(l,mid-1,L,p),solve(mid+1,r,p,R);
}
int main(){
scanf("%lld%lld",&n,&m);
for(ll i=1; i<=n;i++){
scanf("%lld",&a[i]);
}
memset(f,0x3f,sizeof f);
for(ll i=1; i<=n; i++){
f[i][1]=w(1,i);
}
for(ll i=2; i<=m; i++){
k=i,solve(1,n,0,n-1);
}
printf("%lld",f[n][m]);
return 0;
}
完结撒花❀
★,°:.☆( ̄▽ ̄)/$:.°★ 。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】