# 【BZOJ-4380】Myjnie 区间DP

## 4380: [POI2015]Myjnie

Time Limit: 40 Sec  Memory Limit: 256 MBSec  Special Judge
Submit: 162  Solved: 82
[Submit][Status][Discuss]

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

## Solution

$dp[l][r][p]$表示区间$[l,r]$，最小价值为$p$的最大总和，$cnt[k][c]$表示经过$k$位置的费用$\geqslant c$的数量

## Code

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
{
int x=0,f=1; 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;
}
int N,M,a[5050],b[5050],c[5050],C[5050],price[5050],ls[5050],tp,top;
int from[55][55][5050],last[55][55][5050],cnt[55][5050],dp[55][55][5050];
inline void Get(int l,int r,int p)
{
if (l>r) return;
int fr=from[l][r][p],la=last[l][r][p];
//    printf("%d  %d  %d  %d\n",l,r,p,fr);
price[fr]=C[la];
Get(l,fr-1,la); Get(fr+1,r,la);
}
int main()
{
sort(ls+1,ls+tp+1);
for (int i=1; i<=tp; i++) if (ls[top]!=ls[i]) ls[++top]=ls[i];
for (int i=1,x; i<=M; i++) x=lower_bound(ls+1,ls+top+1,c[i])-ls,C[x]=c[i],c[i]=x;
//    for (int i=1; i<=M; i++) printf("%d  ",C[i]); puts("");
for (int l=1; l<=N; l++)
for (int r=l; r<=N; r++)
for (int p=1; p<=M; p++)
dp[l][r][p]=-0x3fffffff;
for (int len=1; len<=N; len++)
for (int l=1,r=l+len-1; r<=N; l++,r++)
{
for (int k=l; k<=r; k++)
for (int i=1; i<=M; i++)
cnt[k][i]=0;
for (int i=1; i<=M; i++)
if (a[i]>=l && b[i]<=r)
for (int k=a[i]; k<=b[i]; k++)
cnt[k][c[i]]++;
for (int k=l; k<=r; k++)
for (int i=M-1; i; i--)
cnt[k][i]+=cnt[k][i+1];
for (int k=l; k<=r; k++)
for (int i=1; i<=M; i++)
if (dp[l][k-1][i]+dp[k+1][r][i]+C[i]*cnt[k][i]>dp[l][r][i])
dp[l][r][i]=dp[l][k-1][i]+dp[k+1][r][i]+C[i]*cnt[k][i],
from[l][r][i]=k,last[l][r][i]=i;// from[l][r][i]=i;
for (int i=M-1; i; i--)
if (dp[l][r][i]<dp[l][r][i+1])
dp[l][r][i]=dp[l][r][i+1],
from[l][r][i]=from[l][r][i+1],last[l][r][i]=last[l][r][i+1];
//                printf("<%d , %d> == %d\n",l,r,dp[l][r][1]);
}
printf("%d\n",dp[1][N][1]);
Get(1,N,1);
for (int i=1; i<=N; i++) printf("%d ",price[i]);
return 0;
}

posted @ 2016-11-10 18:59  DaD3zZ  阅读(553)  评论(0编辑  收藏  举报