CF868F Yet Another Minimization Problem 解题报告
题意翻译
题目描述:给定一个序列 \(a\),要把它分成 \(k\) 个子段。每个子段的费用是其中相同元素的对数。求所有子段的费用之和的最小值。 输入格式:第一行输入 \(n\)(序列长度)和 \(k\)(需分子段数)。接下来一行有 \(n\) 个数,第 \(i\) 个数表示序列的第 \(i\) 个元素 \(a_i\)。 输出格式:输出一个数,费用和的最小值。 \(2 \leq n \leq 10^5\),\(2 \leq k \leq min(n,20)\),\(1 \leq a_i \leq n\) 。
题目描述
You are given an array of $ n $ integers $ a_{1}...\ a_{n} $ . 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 $ k $ 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 $ n $ and $ k $ ( $ 2<=n<=10^{5} $ , $ 2<=k<=min\ (n,20)) $ — the length of the array and the number of segments you need to split the array into. The next line contains $ n $ integers $ a_{1},a_{2},...,a_{n} $ ( $ 1<=a_{i}<=n $ ) — 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: $ [1] $ , $ [1,3] $ , $ [3,3,2,1] $ . The costs are $ 0 $ , $ 0 $ and $ 1 $ , thus the answer is $ 1 $ . In the second example it's optimal to split the sequence in two equal halves. The cost for each half is $ 4 $ . In the third example it's optimal to split the sequence in the following way: $ [1,2,2,2,1] $ , $ [2,1,1,1,2] $ , $ [2,1,1] $ . The costs are $ 4 $ , $ 4 $ , $ 1 $ .
SOLUTION
首先来一波BF~ 🤢
设\(f_{i,j}\)表示前\(i\)个数分成\(j\)段的最小费用
emmm...很好,\(O(kn^2)\),直接寄掉。
于是我们考虑优化
我们可以浅浅发现好像这个dp满足决策单调性
因为\(f_{i,j}\)的最优决策点肯定小于等于\(f_{i+1,j}\)
具体证明:(略)
于是我们就可以通过分治优化dp
接下来的问题就是如何求出\(w(k+1,i)\)了
我们可以借助莫队的思想,挪动l,r端点来达到优化时间的目的
总复杂度\(O(knlogn)\)
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;
}
完结撒花❀
★,°:.☆( ̄▽ ̄)/$:.°★ 。

浙公网安备 33010602011771号