【poj3016】 K-Monotonic

http://poj.org/problem?id=3016 (题目链接)

题意

  给出一个数列,将一个数${a_i}$更改为${b_i}$的代价为${|a_i-b_i|}$。求将数列改为不递减的最小代价

Solution

  话说我现在还没弄得明白→_→感觉论文的证明写的好搓。。

  左转题解:http://www.cnblogs.com/wenruo/p/5798801.html

代码

// poj3016
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<vector>
#include<cstdio>
#include<cmath>
#define LL long long
#define inf 1<<30
#define Pi acos(-1.0)
#define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
using namespace std;

const int maxn=2010;
struct heap {int l,r,val,sz;}q[maxn];
int num[maxn],rt[maxn],a[maxn],b[maxn],c[maxn];
int cnt,n,K,in[maxn][maxn],de[maxn][maxn],f[maxn][maxn];

int newq(int val) {
	q[++cnt].val=val;
	q[cnt].l=q[cnt].r=0;q[cnt].sz=1;
	return cnt;
}
int merge(int x,int y) {
	if (x==0 || y==0) return x+y;
	if (q[x].val<q[y].val) swap(x,y);
	q[x].r=merge(q[x].r,y);
	swap(q[x].l,q[x].r);
	q[x].sz=q[q[x].l].sz+q[q[x].r].sz+1;
	return x;
}
int del(int x) {
	int l=q[x].l,r=q[x].r;
	return merge(l,r);
}
void cal(int *a,int u,int v,int *ans) {
	int res=0,tot=0;cnt=0;
	for (int i=u;i<=v;i++) {
		rt[++tot]=newq(a[i]);
		num[tot]=1;
		while (tot>1 && q[rt[tot]].val<q[rt[tot-1]].val) {
			tot--;
			if (num[tot+1]&1) res+=q[rt[tot]].val-q[rt[tot+1]].val;
			rt[tot]=merge(rt[tot],rt[tot+1]);
			num[tot]+=num[tot+1];
			while (q[rt[tot]].sz*2>num[tot]+1) rt[tot]=del(rt[tot]);
		}
		ans[i]=res;
	}
}
int main() {
	while (scanf("%d%d",&n,&K)!=EOF && n && K) {
		for (int i=1;i<=n;i++) {
			scanf("%d",&a[i]);
			c[i]=-a[i]-i;
			b[i]=a[i]-i;
		}
		for (int i=1;i<=n;i++) {
			cal(c,i,n,de[i]);
			cal(b,i,n,in[i]);
		}
		for (int i=1;i<=n;i++) f[0][i]=inf;
		for (int i=1;i<=K;i++) {
			f[i][0]=0;
			for (int j=1;j<=n;j++) {
				f[i][j]=inf;
				for (int k=0;k<j;k++)
					f[i][j]=min(f[i][j],f[i-1][k]+min(in[k+1][j],de[k+1][j]));
			}
		}
		printf("%d
",f[K][n]);
	}
    return 0;
}
原文地址:https://www.cnblogs.com/MashiroSky/p/6268698.html