1. 程式人生 > >2018.10.27 loj#2292. 「THUSC 2016」成績單(區間dp)

2018.10.27 loj#2292. 「THUSC 2016」成績單(區間dp)

傳送門
g [ i ] [ j ] [ k ]

[ l ] g[i][j][k][l] 表示將區間 l , r l,r
變成最小值等於 k k ,最大值等於 l l 時的花費的最優值。
f [
i ] [ j ] f[i][j]
表示取掉區間 l , r l,r 的最優值。
考慮 g g 陣列的轉移。
g [ i ] [ j + 1 ] [ m i n ( k , w [ j + 1 ] ) ] [ m a x ( l , w [ i + 1 ] ) ] = m i n ( g [ i ] [ j + 1 ] [ m i n ( k , w [ j + 1 ] ) ] [ m a x ( l , w [ i + 1 ] ) ] , g [ i ] [ j ] [ k ] [ l ] ) g[i][j+1][min(k,w[j+1])][max(l,w[i+1])]=min(g[i][j+1][min(k,w[j+1])][max(l,w[i+1])],g[i][j][k][l])
g [ i ] [ t ] [ k ] [ l ] = m i n ( g [ i ] [ t ] [ k ] [ l ] , g [ i ] [ j ] ] [ k ] [ l ] + f [ i + 1 ] [ t ] ) g[i][t][k][l]=min(g[i][t][k][l],g[i][j]][k][l]+f[i+1][t])
然後再用 g g 陣列更新 f f 陣列。
f [ l ] [ r ] = m i n ( f [ l ] [ r ] , g [ l ] [ r ] [ k ] [ l ] ) f[l][r]=min(f[l][r],g[l][r][k][l])
這樣維護就行了。
注意 d p dp 之前離散化一下。
程式碼:

#include<bits/stdc++.h>
using namespace std;
inline int read(){
	int ans=0;
	char ch=getchar();
	while(!isdigit(ch))ch=getchar();
	while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
	return ans;
}
const int N=55;
int n,a,b,f[N][N],g[N][N][N],w[N],x[N],tot=0;
int main(){
	n=read(),a=read(),b=read();
	for(int i=1;i<=n;++i)w[i]=x[i]=read();
	sort(x+1,x+n+1),tot=unique(x+1,x+n+1)-x-1;
	for(int i=1;i<=n;++i)w[i]=lower_bound(x+1,x+tot+1,w[i])-x;
	for(int i=1;i<=n;++i)f[i][i]=a;
	for(int len=2;len<=n;++len)for(int l=1,r=len;r<=n;++l,++r){
		for(int i=l;i<=r;++i)for(int j=tot;j;--j)for(int k=tot;k>=j;--k)g[i][j][k]=0x3f3f3f3f;
		g[l][w[l]][w[l]]=0;
		for(int i=l;i<r;++i)for(int j=tot;j;--j)for(int k=tot;k>=j;--k){
			if(g[i][j][k]==0x3f3f3f3f)continue;
			int&tmp=g[i+1][min(j,w[i+1])][max(k,w[i+1])];
			tmp=min(tmp,g[i][j][k]);
			for(int t=i+1;t<=r;++t)g[t][j][k]=min(g[t][j][k],g[i][j][k]+f[i+1][t]);
		}
		f[l][r]=0x3f3f3f3f;
		for(int i=tot;i;--i)for(int j=tot;j>=i;--j)f[l][r]=min(f[l][r],g[r][i][j]+a+b*(x[i]-x[j])*(x[i]-x[j]));
	}
	cout<<f[1][n];
	return 0;
}