
模型总结
- 决策单调性优化dp
- 采用整体二分的策略确定每个点的最优决策点
关键点
- 整体二分的策略
- 注意复杂度分析,考试不会时可进行尝试
#include<iostream>
#include<cstdio>
#include<cstring>
#define ll long long
using namespace std;
const int inf=1e9;
int read(){
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
return f*x;
}
const int maxn=4e4+5;
int n,k,a[maxn];
ll f[maxn],g[maxn];
int tree[maxn];
void add(int x,int v){
for(;x<=n;x+=(x&-x)) tree[x]+=v;
}
int qry(int x){
int ans=0;
for(;x;x-=(x&-x)) ans+=tree[x];
return ans;
}
void solve(int L,int R,int s,int t){
int mid=(s+t)>>1;
ll tmp=0;
int p=L;
f[mid]=1e18;
for(int i=min(mid-1,R);i>=L;i--){
tmp+=qry(a[i+1]);
add(a[i+1],1);
if(f[mid]>g[i]+tmp){
f[mid]=g[i]+tmp; p=i;
}
}
for(int i=min(mid-1,R);i>=L;i--){
add(a[i+1],-1);
}
if(s<=mid-1) solve(L,p,s,mid-1);
if(mid+1<=t) solve(p,R,mid+1,t);
}
int main(){
n=read(); k=read();
for(int i=1;i<=n;i++) a[i]=read();
ll ans=0;
for(int i=1;i<=n;i++){
ans+=i-1-qry(a[i]);
add(a[i],1);
g[i]=ans;
}
memset(tree,0,sizeof(tree));
for(int i=1;i<k;i++){
solve(1,n,1,n);
for(int j=1;j<=n;j++) g[j]=f[j];
}
printf("%d",g[n]);
return 0;
}