# Bzoj4380 [poi2015]myjnie

## 复杂的区间DP

Posted by yjjr's blog on April 12, 2018

# 题目

## Sample Input

7 5
1 4 7
3 7 13
5 6 20
6 7 1
1 2 5


## Sample Output

43
5 5 13 13 20 20 13


# 分析

$h[x][k]$表示经过x点的$c_i\geq k$的人数

$f[i][j][k]$为区间[i,j]最小值为k的最优方案（仅仅记录下来）

# code

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define dep(i,a,b) for(int i=a;i>=b;i--)
#define ll long long
#define mem(x,num) memset(x,num,sizeof x)
#define reg(x) for(int i=last[x];i;i=e[i].next)
using namespace std;
ll f=1,x=0;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
const int maxn=56,maxm=4e3+6;
int n,m,a[maxm],b[maxm],c[maxm],v[maxm],h[maxn][maxm];
char f[maxn][maxn][maxm];int g[maxn][maxn][maxm],p[maxn][maxn][maxm];
void dfs(int l,int r,int k){
if(l>r)return;
int x=f[l][r][k=p[l][r][k]];
a[x]=v[k],dfs(l,x-1,k),dfs(x+1,r,k);
}
inline int lower(int x){
int l=1,r=m,mid,tmp;
while(l<=r)if(v[mid=(l+r)>>1]<=x)l=(tmp=mid)+1;else r=mid-1;
return tmp;
}
int main(){
sort(v+1,v+1+m);
rep(i,1,m)c[i]=lower(c[i]);
dep(i,n,1)
rep(j,i,n){
rep(k,i,j)rep(x,1,m)h[k][x]=0;
mem(h,0);
rep(k,1,m)if(i<=a[k]&&b[k]<=j)rep(x,a[k],b[k])h[x][c[k]]++;
rep(k,i,j)dep(x,m-1,1)h[k][x]+=h[k][x+1];
dep(k,m,1){
int x,y;
for(x=i,y=0;x<=j;x++){
int tmp=g[i][x-1][k]+g[x+1][j][k]+v[k]*h[x][k];
if(tmp>=y)y=tmp,f[i][j][k]=x;
}
if(y>=g[i][j][k+1])g[i][j][k]=y,p[i][j][k]=k;
else g[i][j][k]=g[i][j][k+1],p[i][j][k]=p[i][j][k+1];
}
}
dfs(1,n,1);
printf("%d\n",g[1][n][1]);
rep(i,1,n)printf("%d ",a[i]);puts("");
return 0;
}