POI2015 MYJ

POI2015 MYJ

考虑从笛卡尔树的角度分析,我们设区间\([l,r]\)中最小值所在的位置为\(i\),则对于任意\([a_i,b_i]\sube [l,r],i\in [a_i,b_i]\),第\(i\)个区间的贡献只取决与店\(i\)的价格

所以设计状态\(dp_{l,r,k}\)表示区间\([l,r]\)中最小值为\(k\)时的最大收入,使用后缀和优化即可

时间复杂度\(O(n^3m)\)

#include<bits/stdc++.h>
using namespace std;
# define ll long long
# define read read1<ll>()
# define Type template<typename T>
Type T read1(){
	T t=0;
	char k;
	bool vis=0;
	do (k=getchar())=='-'&&(vis=1);while('0'>k||k>'9');
	while('0'<=k&&k<='9')t=(t<<3)+(t<<1)+(k^'0'),k=getchar();
	return vis?-t:t;
}
# define fre(k) freopen(k".in","r",stdin);freopen(k".out","w",stdout)
# define ll long long
int s,m,a[4005],b[4005],c[4005],d[4005],f[55][55][4005],g[55][55][4005],h[55][55][4005];
void pr(int l,int r,int p){
	if(l>r)return;
	p=h[l][r][p];
//	cout<<l<<' '<<r<<' '<<p<<endl;
	if(l==r){printf("%d ",d[p]);return;}
	for(int i=l;i<=r;++i)
		if(f[l][r][p]==f[l][i-1][p]+f[i+1][r][p]+d[p]*(-g[l][i-1][p]-g[i+1][r][p]+g[l][r][p])){
			pr(l,i-1,p);
			printf("%d ",d[p]);
			pr(i+1,r,p);
			return;
		}
	assert(0);
}void Max(int &x,int v){if(v>x)x=v;}
int main(){
	s=read,m=read;
	for(int i=1;i<=m;++i)
		a[i]=read,b[i]=read,c[i]=d[i]=read;
	sort(d+1,d+m+1);*d=unique(d+1,d+m+1)-d-1;
	for(int i=1;i<=m;++i)c[i]=lower_bound(d+1,d+*d+1,c[i])-d;
	for(int i=1;i<=m;++i)
		++g[a[i]][b[i]][c[i]];
	for(int i=s;i--;)
		for(int j=i+1;j<=s;++j)
			for(int k=*d;k;--k)
				g[i][j][k]+=g[i][j-1][k]+g[i+1][j][k]-g[i+1][j-1][k];
	for(int i=s;i;--i)
		for(int j=i;j<=s;++j)
			for(int k=*d;k;--k)
				g[i][j][k]+=g[i][j][k+1];
	for(int i=s;i;--i)
		for(int j=i;j<=s;++j)
			for(int l=*d;l;--l){
				for(int k=i;k<=j;++k)
					Max(f[i][j][l],f[i][k-1][l]+f[k+1][j][l]+d[l]*(-g[i][k-1][l]-g[k+1][j][l]+g[i][j][l]));
				if(!h[i][j][l+1]||f[i][j][h[i][j][l+1]]<=f[i][j][l])h[i][j][l]=l;
				else h[i][j][l]=h[i][j][l+1],f[i][j][l]=f[i][j][l+1];
			}
	printf("%d\n",f[1][s][1]);
	pr(1,s,1);
	return 0;
}
posted @ 2021-09-02 17:12  ファイナル  阅读(43)  评论(0)    收藏  举报