[JZOJ4931] A

来源:互联网 发布:工艺流程图制作软件 编辑:程序博客网 时间:2024/05/16 16:14

Description

有N家洗车店从左往右排成一排,每家店都有一个正整数价格Pi。
有M个人要来消费,第i个人会驶过第Ai个开始一直到第Bi个洗车店,且会选择这些店中最便宜的一个进行一次消费。但是如果这个最便宜的价格大于Ci,那么这个人就不洗车了。
请给每家店指定一个价格,使得所有人花的钱的总和最大。
所有数据满足N<=50,M<=4000,1<=Ai<=Bi<=N,1<=Ci<=500000
本题开O2

Solution

既然开了O2,那就要有梦想。

考虑区间DP

首先显然每家洗车店取值只有4000种
f[l][r][i]表示[l,r]内,最小值为i的贡献,并且有贡献的区间要全部在[l,r]内。

然后再设g[i][j]表示[l,r]条件下,i这个位置有多少人能选j

那么g[i][j]可以先求,然后再转移

枚举p,那么f[l][r][i]可以从f[l][p1][i],f[p+1][r][i]转移来。(这里为了优化,我们将i设为i~max的最大值)
复杂度是O(N3M)

然而这是能跑过的。

故曰:人不可一日无梦想

Code

#include <cstdio>#include <cstdlib>#include <algorithm>#include <iostream>#include <cstring>#include <cmath>#define fo(i,a,b) for(int i=a;i<=b;i++)#define fod(i,a,b) for(int i=a;i>=b;i--)#define LL long long #define N 55#define M 4005using namespace std;struct node{    int x,y,c;}a[M];bool cmp(node x,node y){    return x.c>y.c;}int n,m,f[N][N][M],g[N][M],b[N][M];int main(){    cin>>n>>m;    fo(i,1,m) scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].c);    sort(a+1,a+m+1,cmp);    memset(f,0,sizeof(f));    int ans=0;    fo(len,1,n)    {        fo(l,1,n-len+1)        {            int r=l+len-1;            memset(b,0,sizeof(b));            fo(i,l,r)            {                fo(j,1,m)                {                    g[i][j]=0;                    if(a[j].y==i-1&&a[j].x>=l) b[i][j]--;                    if(a[j].x==i&&a[j].y<=r) b[i][j]++;                    b[i][j]+=b[i-1][j];                    g[i][j]+=g[i][j-1]+b[i][j];                 }            }            fo(i,l,r)            {                fo(j,1,m)                {                    f[l][r][j]=max(f[l][r][j],f[l][i-1][j]+f[i+1][r][j]+g[i][j]*a[j].c);                    f[l][r][j]=max(f[l][r][j],f[l][r][j-1]);                    ans=max(ans,f[l][r][j]);                }            }        }    }       cout<<ans;}
0 0