思路:
设表示前
个数分成
段的最小花费,那么显然有
一个满足决策单调性的充要条件是:对于两个决策点
,若在
处
优于
,则在
处
都优于
。
定理:若满足四边形不等式,则
满足决策单调性。
定义:若二元函数满足
,则称其满足四边形不等式。
推论,若只与
有关,即
,则必然符合四边形不等式。且此时,该类
适宜用单调队列优化。
而这题是满足的,若
在
都出现了,则不等式右边比左边多出
的贡献,其它情况一样。假设区间
的中点为
、决策区间为
,那么
可以先求出
,并得到最优决策点
;接着递归处理
注意到每次递归处理时决策区间的左端点是递增的,所以我们有了莫队的思路,而左端点递增保证了其一层的移动指针复杂度是线性的。暴力更新值的复杂度平摊下来是
。
MyCode:
#include<bits/stdc++.h>
using namespace std;
const int maxn=4e4;
int f[maxn][105],last[maxn],nex[maxn],pre[maxn],a[maxn];
int now,pl=1,pr,sum;
int cost(int l,int r) {
while(pl<l) {
if(nex[pl]<=pr) sum-=nex[pl]-pl;
pl+=1;
}
while(pl>l) {
pl-=1;
if(nex[pl]<=pr) sum+=nex[pl]-pl;
}
while(pr>r) {
if(pre[pr]>=pl) sum-=pr-pre[pr];
pr-=1;
}
while(pr<r) {
pr+=1;
if(pre[pr]>=pl) sum+=pr-pre[pr];
}
return sum;
}//莫队
void solve(int l,int r,int x,int y) {
if( l>r ) return;
int mid=l+r>>1,tmp,val=0x3f3f3f3f,pos;
for(int i=x;i<mid&&i<=y;++i) {
tmp=f[i][now-1]+cost(i+1,mid);
if(tmp<val) val=tmp,pos=i;
}
f[mid][now]=val;
solve(l,mid-1,x,pos);
solve(mid+1,r,pos,y);
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
int n,k;
cin>>n>>k;
for(int i=1;i<=n;++i) {
cin>>a[i];
pre[i]=last[a[i]];
last[a[i]]=i;
}
for(int i=1;i<=n;++i) {
last[a[i]]=n+1;
f[i][0]=0x3f3f3f3f;
}//f[0][0]=0
for(int i=n;i;--i) {
nex[i]=last[a[i]];
last[a[i]]=i;
}
for(int i=1;i<=k;++i) now=i,solve(1,n,0,n);
cout<<f[n][k]<<'\n';
return 0;
} 
京公网安备 11010502036488号