bzoj [POI2015]Myjnie

[POI2015]Myjnie

Time Limit: 40 Sec Memory Limit: 256 MBSec Special Judge

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],ci

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

这个区间dp有点东西。。。
离散化一下
f[l][r][t] 表示完全属于区间的人中最小值刚好是t的最优贡献。
g[l][r][t] 表示完全属于区间的人中最小值大于等于t的最优贡献。
然后你的转移就成了枚举最小值是哪个店。
f[l][r][t]=max(g[l][i-1][t]+g[i+1][r][t]+cost(i))
然而这个cost(i)有点尴尬。。。你可能还有有个预处理h[i][j]表示在处理当前这个dp区间的情况下,包含i这个位置的人且在最小值为j的情况下能给钱的人有多少个。。。
写吧~

1 mol 乱七八糟的错误。。。。。调一万年啊。。。。


#include<bits/stdc++.h>
using namespace std;
const int maxm = 4004;
struct lpl{
    int a, b, c;
}ini[maxm];
struct lpd{
    int g, f, pos;
}dp[55][55][maxm];
int n, m, k, ans[55], pl[maxm], nam[maxm], mark[500005], h[55][maxm];

inline bool cmp(lpl A, lpl B) {return A.b == B.b ? A.a < B.a : A.b < B.b;}

inline void putit()
{
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= m; ++i) scanf("%d%d%d", &ini[i].a, &ini[i].b, &ini[i].c), pl[i] = ini[i].c;
    sort(ini + 1, ini + m + 1, cmp);
    sort(pl + 1, pl + m + 1); k = 0;
    for(int i = 1; i <= m; ++i)
        if(pl[i] != pl[i - 1]){
            k++; nam[k] = pl[i]; mark[pl[i]] = k;
        }
    for(int i = 1; i <= m; ++i) ini[i].c = mark[ini[i].c];
}

inline void workk()
{
    for(int l = n; l >= 1; --l)
        for(int r = l; r <= n; ++r){
            for(int i = l; i <= r; ++i)
                for(int j = 1; j <= k; ++j)
                    h[i][j] = 0;
            for(int i = 1; i <= m && ini[i].b <= r; ++i){
                if(ini[i].a < l) continue;
                for(int j = ini[i].a; j <= ini[i].b; ++j) h[j][ini[i].c]++;
            }
            for(int i = l; i <= r; ++i)
                for(int j = k - 1; j >= 1; --j)
                    h[i][j] += h[i][j + 1];
            for(int i = l; i <= r; ++i)
                for(int j = k; j >= 1; --j){
                    int tmp = dp[l][i - 1][j].g + dp[i + 1][r][j].g + h[i][j] * nam[j];
                    if(dp[l][r][j].f < tmp){
                        dp[l][r][j].f = tmp; dp[l][r][j].pos = i;
                    }
                    dp[l][r][j].g = max(dp[l][r][j].f, dp[l][r][j + 1].g);
                }
        }
}

void dfs(int l, int r, int t)
{
    if(l > r) return;
    if(dp[l][r][t].g == 0){
        for(int i = l; i <= r; ++i) ans[i] = nam[t];
        return;
    }
    for(int i = t; i <= k; ++i){
        if(dp[l][r][t].g == dp[l][r][i].f){
            int now = dp[l][r][i].pos;
            ans[now] = nam[i];
            dfs(l, now - 1, i); dfs(now + 1, r, i);
            break;
        }
    }
}

inline void print()
{
    printf("%d\n", dp[1][n][1].g);
    dfs(1, n, 1);
    for(int i = 1; i <= n; ++i) printf("%d ", ans[i]);
}

int main()
{
    putit();
    workk();
    print();
    return 0;
} 

原文地址:https://www.cnblogs.com/LLppdd/p/9175978.html

时间: 2024-12-29 07:04:09

bzoj [POI2015]Myjnie的相关文章

[POI2015]Myjnie

[POI2015]Myjnie 题目大意: 有\(n(n\le50)\)家洗车店从左往右排成一排,每家店都有一个正整数价格\(d_i\). 有\(m(m\le4000)\)个人要来消费,第\(i\)个人会选择\(a_i\sim b_i\)这些店中最便宜的一个进行一次消费.但是如果这个最便宜的价格大于\(c_i\),那么这个人就不洗车了. 请给每家店指定一个价格,使得所有人花的钱的总和最大. 思路: 将\(c\)离散化后进行区间DP. 用\(f_{i,j,k}\)表示区间\([i,j]\)最小值为

BZOJ 4380 [POI2015]Myjnie | DP

链接 BZOJ 4380 题面 有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],ci Output 第

@bzoj - [email&#160;protected] [POI2015] Myjnie

目录 @[email protected] @[email protected] @accepted [email protected] @[email protected] @[email protected] 有 n 家洗车店从左往右排成一排,每家店都有一个正整数价格 p[i]. 有 m 个人要来消费,第 i 个人会驶过第 a[i] 个开始一直到第 b[i] 个洗车店,且会选择这些店中最便宜的一个进行一次消费.但是如果这个最便宜的价格大于 c[i],那么这个人就不洗车了. 请给每家店指定一个

BZOJ4380 : [POI2015]Myjnie

将$c$离散化,设: $f[i][j][k]$为区间$[i,j]$最小值为$k$的最大收益. $g[i][j][k]$为$\max(g[i][j][k..m])$. $h[i][j]$为对于当前DP区间,经过$i$点的,费用限制$\geq j$的人数. 然后直接DP即可,时间复杂度$O(n^3m)$. #include<cstdio> #include<algorithm> const int N=52,M=4002; int n,m,i,j,k,x,y,t,a[M],b[M],c

@bzoj - [email&#160;protected] [POI2015] Kinoman

目录 @[email protected] @[email protected] @accepted [email protected] @[email protected] @[email protected] 共有 m 部电影,第 i 部电影的好看值为 w[i]. 在 n 天之中每天会放映一部电影,第 i 天放映的是第 f[i] 部. 你可以选择 l, r (1 <= l <= r <= n) ,并观看第 l, l+1, -, r 天内所有的电影. 最大化观看且仅观看过一次的电影的好

bzoj 4385: [POI2015]Wilcze do?y

4385: [POI2015]Wilcze do?y Description 给定一个长度为n的序列,你有一次机会选中一段连续的长度不超过d的区间,将里面所有数字全部修改为0.请找到最长的一段连续区间,使得该区间内所有数字之和不超过p. Input 第一行包含三个整数n,p,d(1<=d<=n<=2000000,0<=p<=10^16).第二行包含n个正整数,依次表示序列中每个数w[i](1<=w[i]<=10^9). Output 包含一行一个正整数,即修改后能

BZOJ 3747: [POI2015]Kinoman( 线段树 )

线段树... 我们可以枚举左端点 , 然后用线段树找出所有右端点中的最大值 . ----------------------------------------------------------------------------------------- #include<cstdio> #include<algorithm> #include<cstring> #include<iostream> #define rep( i , n ) for( i

【BZOJ 3747】 3747: [POI2015]Kinoman (线段树)

3747: [POI2015]Kinoman Time Limit: 60 Sec  Memory Limit: 128 MBSubmit: 830  Solved: 338 Description 共有m部电影,编号为1~m,第i部电影的好看值为w[i]. 在n天之中(从1~n编号)每天会放映一部电影,第i天放映的是第f[i]部. 你可以选择l,r(1<=l<=r<=n),并观看第l,l+1,-,r天内所有的电影.如果同一部电影你观看多于一次,你会感到无聊,于是无法获得这部电影的好看值

BZOJ 4384: [POI2015]Trzy wie?e

4384: [POI2015]Trzy wie?e Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 217  Solved: 61[Submit][Status][Discuss] Description 给定一个长度为n的仅包含'B'.'C'.'S'三种字符的字符串,请找到最长的一段连续子串,使得这一段要么只有一种字符,要么有多种字符,但是没有任意两种字符出现次数相同. Input 第一行包含一个正整数n(1<=n<=1000000),表示字符