洗车
https://class.51nod.com/Html/Textbook/ChapterIndex.html#textbookId=126&chapterId=336
如果我们考虑 \(f[i][j]\) 表示假设只有区间 \([i,j]\),经过这个区间的人购买的最大值,发现转移时有些人会反悔,抛弃较大值,取当前最小的,会要减去之前的答案,不方便操作。
于是我们设 \(f[i][j]\) 表示假设只有区间 \([i,j]\),且 \([a_i,b_i]\in[i,j]\) 的人。
发现我们不知道商店的价格,所以改为 \(f[i][j][k]\),\(k\) 表示价格最低是多少(显然定价一定是某个 \(c_i\)),经过离散化至多有 \(m\) 种。
枚举价格最低是 \(p\),
显然的性质:由于最低位置是 \(p\),所以只要是包含位置 \(p\) 的人,能到这里消费一定到这里消费。因为 \(k1,k2\ge k\)
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=60,M=4010;
int f[N][N][M],g[N][N][M];
int n,m,a[M],K,b[M],c[M],ls[M],cnt[M],lst[M];
void print(int i,int j,int k){
printf("f[%d][%d][%d]=%d\n",i,j,k,f[i][j][k]);
}
void printg(int i,int j,int k){
printf("g[%d][%d][%d]=%d\n",i,j,k,g[i][j][k]);
}
void out(){
for(int l=1;l<=n;++l)
for(int r=l;r<=n;++r,puts("\n"))
for(int k=1;k<=K;++k)
print(l,r,k);
}
int main(){
#ifdef LOCAL
freopen("1.txt","r",stdin);
#endif
#ifndef LOCAL
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
#endif
cin>>n>>m;
for(int i=1;i<=m;++i)cin>>a[i]>>b[i]>>c[i],ls[i]=c[i];
sort(ls+1,ls+1+m);
K=unique(ls+1,ls+1+m)-ls-1;
for(int i=1;i<=m;++i)c[i]=lower_bound(ls+1,ls+1+K,c[i])-ls;
for(int len=1;len<=n;++len)
for(int l=1;l+len-1<=n;++l){
int r=l+len-1;
int tot=0;
for(int i=1;i<=m;++i)
if(l<=a[i]&&b[i]<=r)lst[++tot]=i;
for(int p=l;p<=r;++p){
memset(cnt+1,0,K*4);
for(int i=1;i<=tot;++i)
if(a[lst[i]]<=p&&p<=b[lst[i]])++cnt[c[lst[i]]];
for(int i=K;i;--i){
cnt[i]+=cnt[i+1];
f[l][r][i]=max(g[l][p-1][i]+g[p+1][r][i]+cnt[i]*ls[i],f[l][r][i]);
}
}
for(int i=K;i;--i)g[l][r][i]=max(g[l][r][i+1],f[l][r][i]);
}
// out();
cout<<g[1][n][1];
return 0;
}