BZOJ 1564: [NOI2009]二叉查找树

听说n<=70?

我一直以为n<=400000......

区间DP

#include<cstdio>
#include<algorithm>
using namespace std;
int n,K,F[105][105][105],b[105],Sum[105];
struct node{
	int sum,id,val;
}a[105];
bool cmp(node a,node b){
	return a.sum<b.sum;
}
int main(){
	scanf("%d%d",&n,&K);
	for (int i=1; i<=n; i++) scanf("%d",&a[i].sum);
	for (int i=1; i<=n; i++) scanf("%d",&a[i].id);
	for (int i=1; i<=n; i++) b[i]=a[i].id;
	for (int i=1; i<=n; i++) scanf("%d",&a[i].val);
	sort(a+1,a+n+1,cmp);
	sort(b+1,b+n+1);
	int N=unique(b+1,b+n+1)-b-1;
	for (int i=1; i<=n; i++) a[i].id=lower_bound(b+1,b+N,a[i].id)-b;
	for (int i=1; i<=n; i++)
		for (int j=i; j<=n; j++)
			for (int k=0; k<=N; k++)
				F[i][j][k]=1e9;
	for (int i=1; i<=n; i++) Sum[i]=Sum[i-1]+a[i].val;
	for (int i=1; i<=n; i++)
		for (int k=0; k<=N; k++){
			F[i][i][k]=a[i].val;
			if (k>a[i].id) F[i][i][k]+=K;
		}
	for (int len=1; len<n; len++)
		for (int i=1; i<n; i++){
			int j=i+len;
			if (j>n) break;
			for (int lim=0; lim<=N; lim++)
				for (int k=i; k<=j; k++){
					F[i][j][lim]=min(F[i][j][lim],F[i][k-1][lim]+F[k+1][j][lim]+K+Sum[j]-Sum[i-1]);
					if (lim<=a[k].id) F[i][j][lim]=min(F[i][j][lim],F[i][k-1][a[k].id]+F[k+1][j][a[k].id]+Sum[j]-Sum[i-1]);
				}
		}
	int ans=1e9;
	for (int i=0; i<=N; i++) ans=min(ans,F[1][n][i]);
	printf("%d\n",ans);
	return 0;
}

  

posted @ 2018-11-07 19:21  ~Silent  阅读(152)  评论(0编辑  收藏  举报
Live2D