您的位置:首页 > 其它

BZOJ4380 POI2015 Myjnie

2016-11-12 16:46 711 查看
Description

有n家洗车店从左往右排成一排,每家店都有一个正整数价格p[i]。

有m个人要来消费,第i个人会驶过第a[i]个开始一直到第b[i]个洗车店,且会选择这些店中最便宜的一个进行一次消费。但是如果这个最便宜的价格大于c[i],那么这个人就不洗车了。

请给每家店指定一个价格,使得所有人花的钱的总和最大。

Input

第一行包含两个正整数n,m(1≤n≤50,1≤m≤4000)。

接下来m行,每行包含三个正整数a[i],b[i],c[i] (1≤a[i]≤b[i]≤n,1≤c[i]≤5×105)

Output

第一行输出一个正整数,即消费总额的最大值。

第二行输出n个正整数,依次表示每家洗车店的价格p[i],要求1<=p[i]<=500000。

若有多组最优解,输出任意一组。

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

Solution:

玄学三维dp,膜Claris大犇

还是提醒自己先不要考虑方案输出。事实证明先考虑方案就会想到贪心爆搜等奇怪的思路上。

对于当前这个询问区间,它的贡献是vali={min[L,R]0min[L,R]≤Limitimin[L,R]>Limiti。

思考对象为区间的话感觉没有什么思路,我们考虑每个洗车店对答案的贡献:在什么情况下,哪些车辆会在当前的洗车店消费?

在某段区域内,当前这个洗车店为最小值,就会导致在该区域内并且经过该洗车店的车辆在此处进行消费。

于是我们按照上述内容进行dp就好了,定义dp[L][R][k]表示在区间[L,R]内,该区间的最小值最小为k时,全部路程在[L,R]内的汽车的最优总贡献。之后枚举哪一家洗车店的价格定为k,统计区间经过当前洗车店,并且Limiti≥k的车辆总数,记为h[i][k]。于是得到转移方程式(显然这个k我们需要离散,对应的数组在我的代码中记作res[k]):

dp[L][R][k]=max{dp[L][p−1][k]+dp[p+1][R][k]+res[k]×h[p][k]dp[L][R][w]p∈[L,R]w∈[k,m]

这样最优解就得到了,接下来打印方案的话,我们存储从哪个洗车店转移此时洗车店的最优定价(因为我们关于dp的定义没有确定当前枚举的消费值就是最优解……)。类似二叉树一样不断将区间劈成两部分递归处理即可。对应到我的代码中分别为f数组和v数组。

最后总复杂度为O(n3m)(果然数据范围小没什么好事情……)。

就当做是补充Claris大犇短小的题解吧2333

#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 55
#define M 4005
template <class temp>
inline bool check_max(temp &a,temp b){
if(a>=b)return false;
a=b;return true;
}
int dp

[M],v

[M],f

[M],h
[M];
int a[M],b[M],c[M],res[M];
int ans[M];
void dfs(int l,int r,int col){
if(l>r)return;
int mid=f[l][r][col];
ans[mid]=v[l][r][col];
col=v[l][r][col];
dfs(l,mid-1,col),dfs(mid+1,r,col);
}
int main(){
int n,m;
scanf("%d %d",&n,&m);
for(int i=1;i<=m;i++){
scanf("%d %d %d",&a[i],&b[i],&c[i]);
res[i]=c[i];
}
std::sort(res+1,res+m+1);
for(int i=1;i<=m;i++)
c[i]=std::lower_bound(res+1,res+m+1,c[i])-res;
for(int t=1;t<=n;t++)
for(int l=1;l+t-1<=n;l++){
int r=l+t-1;

for(int i=l-1;i<=r;i++)
for(int j=1;j<=m;j++)h[i][j]=0;
for(int i=1;i<=m;i++)
if(l<=a[i]&&b[i]<=r)
h[a[i]][c[i]]++,h[b[i]+1][c[i]]--;
for(int j=1;j<=m;j++)
for(int i=l;i<=r;i++)h[i][j]+=h[i-1][j];
for(int i=l;i<=r;i++)
for(int j=m;j>=1;j--)h[i][j]+=h[i][j+1];

for(int k=m;k>=1;k--){
f[l][r][k]=l,v[l][r][k]=k;
for(int i=l;i<=r;i++)
if(check_max(dp[l][r][k],dp[l][i-1][k]+dp[i+1][r][k]+res[k]*h[i][k]))
f[l][r][k]=i,v[l][r][k]=k;
}

for(int k=m-1;k>=1;k--)
if(check_max(dp[l][r][k],dp[l][r][k+1]))
f[l][r][k]=f[l][r][k+1],v[l][r][k]=v[l][r][k+1];
}
printf("%d\n",dp[1]
[1]);

dfs(1,n,1);
printf("%d",(!ans[1])?res[m]:res[ans[1]]);
for(int i=2;i<=n;i++)
printf(" %d",(!ans[i])?res[m]:res[ans[i]]);
putchar('\n');
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息