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
的贡献,并且有贡献的区间要全部在
然后再设
g[i][j]
表示
[l,r]
条件下,
i
这个位置有多少人能选
那么 g[i][j] 可以先求,然后再转移
枚举
p
,那么
复杂度是
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 4005
using 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;
}