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; }