洗车Myjnie 题解

题意:给定 a [ i ] a[i] a[i] b [ i ] b[i] b[i],给个数的贡献是 [ a [ i ] , b [ i ] ] [a[i],b[i]] [a[i],b[i]]区间内不超过 c [ i ] c[i] c[i]的值中的最小值

请给出最大值和每个贡献 p [ i ] p[i] p[i],使得最后的答案最大。

若存在多组随便输出一组就行。

为啥这题给放到区间DP

没看出来啊

I.普通DP

a s d [ i ] [ j ] asd[i][j] asd[i][j]表示 [ i , j ] [i,j] [i,j]所能提供的最大贡献。

但是这个方程很难转移

并且,由于转移的过程中还需要记录具体的取值,所以需要一个 q w e qwe qwe数组来记录

q w e [ i ] [ j ] qwe[i][j] qwe[i][j]表示区间 [ i , j ] [i,j] [i,j]中的最小值

并且上面的 [ i , j ] [i,j] [i,j]都是固定的(即题目给定的 a [ i ] a[i] a[i] b [ i ] b[i] b[i]

但是这道题需要在调整中寻找最优解

考虑再加一维。

a s d [ i ] [ j ] [ k ] asd[i][j][k] asd[i][j][k]表示区间 [ i , j ] [i,j] [i,j],最小值 ≥ k \geq k k 所提供的最大贡献。

最终的答案就是 a s d [ 1 ] [ n ] [ 1 ] asd[1][n][1] asd[1][n][1]

q w e [ i ] [ j ] [ k ] qwe[i][j][k] qwe[i][j][k]表示区间 [ i , j ] [i,j] [i,j]中的最小值 ≥ k \geq k k所造成的最优解的最小值的取值

一个结论:

一定存在一种方案,使得每家洗车店的价格 p ∈ c p\in c pc


一个转移:

a s d [ i ] [ j ] [ k ] = m a x ( a s d [ i ] [ j ] [ k + 1 ] , c o s t ( i , j , k ) ) asd[i][j][k]=max(asd[i][j][k+1],cost(i,j,k)) asd[i][j][k]=max(asd[i][j][k+1],cost(i,j,k))

其中cost(i,j,k)表示 [ i , j ] [i,j] [i,j]的最小值正好取到 k k k时的最大贡献。

再用 v [ i ] [ j ] v[i][j] v[i][j]表示 i i i位置上容忍度 ≥ j \geq j j的人数

最终的转移方程就是:

cost(i,j,k)=max(asd[i][p-1][k]+asd[p+1][j][k]+v[p][k]*k);

但是还需要输出方案

通过上面所描述的做法,我们只需要记录第三维转移的具体值 q w e qwe qwe和区间转移的具体位置 p p p 即可输出方案

#include<bits/stdc++.h>
using namespace std;
#define f1(a,b,c) for(int c=a;c<=b;c++)
#define f2(a,b,c) for(int c=a;c>=b;c--)
#define f3(a,b,c) for(int c=a;c;c=b)
#define so1(a,n) sort(a+1,a+n+1,mycmp);
#define so2(a,n) sort(a+1,a+n+1);
#define ll long long
#define itn int
#define ubt int 
const int twx=5e3+100;
const int N=60;
const int inf=0x3f3f3f3f;
ll read()
{
    ll sum=0;
    ll flag=1;
    char c=getchar();
    while(c<'0'||c>'9')
    {
        if(c=='-')
        {
            flag=-1;
        }
        c=getchar();
    }
    while(c>='0'&&c<='9')
    {
        sum=((sum*10)+c-'0');
        c=getchar();
    }
    return sum*flag;
}
int n,m;
int a[twx];
int b[twx];
int c[twx];
int d[twx];
int ans[N];
int asd[N][N][twx];
int qwe[N][twx];
int h[N][N][twx];
int pre[N][N][twx];
void print(int l,int r,int p)
{
	if(l>r)
	{
		return;
	}
	p=pre[l][r][p];
	int k=h[l][r][p];
	ans[k]=d[p];
	print(l,k-1,p);
	print(k+1,r,p);
	return;
}
void init()
{
	n=read();
    m=read();
    f1(1,m,i)
    {
        a[i]=read();
        b[i]=read();
        c[i]=d[i]=read();
    }
    so2(d,m)
    int cnt=unique(d+1,d+m+1)-d-1;
    f1(1,m,i)
    {
        c[i]=lower_bound(d+1,d+cnt+1,c[i])-d;
    }
    f1(1,n,len)
    {
        f1(1,n-len+1,i)
        {
            int j=i+len-1;
            memset(qwe,0,sizeof qwe); 
            f1(1,m,k)
            {
                if(i<=a[k]&&b[k]<=j)
                {
                    f1(a[k],b[k],p)
                    {
                        ++qwe[p][c[k]];
                    }
                }
            }
            f1(i,j,k)
            {
                f2(cnt,1,p)
                {
                    qwe[k][p]+=qwe[k][p+1];
                }
            }
            f2(cnt,1,k)
            {
                int MAX=0;
                f1(i,j,p)
                {
                    if(MAX<=asd[i][p-1][k]+asd[p+1][j][k]+qwe[p][k]*d[k])
					{
						MAX=asd[i][p-1][k]+asd[p+1][j][k]+qwe[p][k]*d[k];
						h[i][j][k]=p;//记录转移位置 
					}
                }
                if(MAX>=asd[i][j][k+1])
                {
                    asd[i][j][k]=MAX;
                    pre[i][j][k]=k;
                }
                else
                {
                    asd[i][j][k]=asd[i][j][k+1];
                    pre[i][j][k]=pre[i][j][k+1];
                }
            }
        }
    }
    printf("%d\n",asd[1][n][1]);
	print(1,n,1);
	f1(1,n,i)
	{
		printf("%d ",ans[i]);
	}
}
void work()
{
	
}
void print()
{
	
}
int main()
{
	//freopen(".in","r",stdin);
	//freopen(".out","w",stdout);
    init();
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值