区间DP 去%栋老师吧
我写得不够优越,h数组复杂了
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; const int maxn=51; const int maxm=4001; struct node{int l,r,c;}p[maxm]; int lslen,ls[maxm]; int f[maxn][maxn][maxm],g[maxn][maxn][maxm];//当前区间的最小值为c的最大收益 g是f的后缀最大值 int h[maxn][maxn][maxm];//有多少ci大于等于c的人 //simple int u[maxn][maxn][maxm],q[maxn][maxn][maxm];//f这个状态转移的断点 g这个最大来自于那个f //reback int as[maxn]; void dfs(int l,int r,int c) { if(l>r)return ; int p=q[l][r][c]; int k=u[l][r][p]; as[k]=p; dfs(l,k-1,p); dfs(k+1,r,p); } int main() { freopen("a.in","r",stdin); freopen("a.out","w",stdout); int n,m; scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) { scanf("%d%d%d",&p[i].l,&p[i].r,&p[i].c); ls[++lslen]=p[i].c; } sort(ls+1,ls+lslen+1); lslen=unique(ls+1,ls+lslen+1)-ls-1; for(int i=1;i<=m;i++) p[i].c=lower_bound(ls+1,ls+lslen+1,p[i].c)-ls; for(int l=1;l<=n;l++) for(int r=l;r<=n;r++) { for(int i=1;i<=m;i++) if(l<=p[i].l&&p[i].r<=r)h[l][r][p[i].c]++; for(int c=lslen;c>=1;c--) h[l][r][c]+=h[l][r][c+1]; } for(int i=1;i<=n;i++) for(int c=lslen;c>=1;c--) { f[i][i][c]=ls[c]*h[i][i][c]; u[i][i][c]=i; if(g[i][i][c+1]>f[i][i][c])g[i][i][c]=g[i][i][c+1],q[i][i][c]=q[i][i][c+1]; else g[i][i][c]=f[i][i][c],q[i][i][c]=c; } for(int L=2;L<=n;L++) for(int l=1;l+L-1<=n;l++) { int r=l+L-1; for(int c=lslen;c>=1;c--) for(int k=l;k<=r;k++) { int d=g[l][k-1][c]+g[k+1][r][c]+(h[l][r][c]-h[l][k-1][c]-h[k+1][r][c])*ls[c]; if(f[l][r][c]<=d) { f[l][r][c]=d; u[l][r][c]=k; if(g[l][r][c+1]>f[l][r][c])g[l][r][c]=g[l][r][c+1],q[l][r][c]=q[l][r][c+1]; else g[l][r][c]=f[l][r][c],q[l][r][c]=c; } } } printf("%d\n",g[1][n][1]); dfs(1,n,1); for(int i=1;i<n;i++)printf("%d ",ls[as[i]]); printf("%d\n",ls[as[n]]); return 0; }