BZOJ1564 NOI2009二叉查找树(区间dp)
首先按数据值排序,那么连续一段区间的dfs序一定也是连续的。
将权值离散化,设f[i][j][k]为i到j区间内所有点的权值都>=k的最小代价,转移时枚举根考虑是否修改权值即可。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } #define N 75 int n,m,b[N],f[N][N][N],sum[N]; struct data { int x,y,z; bool operator <(const data&a) const { return x<a.x; } }a[N]; int main() { #ifndef ONLINE_JUDGE freopen("bzoj1564.in","r",stdin); freopen("bzoj1564.out","w",stdout); const char LL[]="%I64d\n"; #else const char LL[]="%lld\n"; #endif n=read(),m=read(); for (int i=1;i<=n;i++) a[i].x=read(); for (int i=1;i<=n;i++) b[i]=a[i].y=read(); for (int i=1;i<=n;i++) a[i].z=read(); sort(a+1,a+n+1);sort(b+1,b+n+1); for (int i=1;i<=n;i++) a[i].y=lower_bound(b+1,b+n+1,a[i].y)-b; for (int i=1;i<=n;i++) sum[i]=sum[i-1]+a[i].z; memset(f,42,sizeof(f)); for (int i=1;i<=n;i++) { for (int k=1;k<=n;k++) f[i][i-1][k]=0; for (int k=1;k<=a[i].y;k++) f[i][i][k]=a[i].z; for (int k=a[i].y+1;k<=n;k++) f[i][i][k]=a[i].z+m; } for (int k=1;k<=n;k++) f[n+1][n][k]=0; for (int k=2;k<=n;k++) for (int i=1;i<=n-k+1;i++) { int j=i+k-1; for (int root=i;root<=j;root++) { f[i][j][a[root].y]=min(f[i][j][a[root].y],f[i][root-1][a[root].y]+f[root+1][j][a[root].y]+sum[j]-sum[i-1]); for (int d=1;d<=n;d++) f[i][j][d]=min(f[i][j][d],f[i][root-1][d]+f[root+1][j][d]+sum[j]-sum[i-1]+m); } for (int d=n;d>=1;d--) f[i][j][d]=min(f[i][j][d],f[i][j][d+1]); } cout<<f[1][n][1]; return 0; }