6894. 【2020.11.25提高组模拟】小 S 埋地雷 (loj6611. 摧毁时间线)

\(n\)个东西,你需要钦定一个顺序删掉物品,删掉一个物品的贡献的式子为\((p_{i-1}-q_i)^2+(p_i-r_{i+1})^2+(p_{i+1}-s_{i+2})^2\),其中\(i\)表示当前这个物品,\(i-1\)表示当前剩下的物品中的上一个(左边)。如果实际上不存在\(i-1\),那么当做\(0\)\(i+1,i+2\)类似

问最大的贡献和。

\(n\le 70\)


比赛时看错题意了……

不考虑\((p_{i+1}-s_{i+2})^2\)。显然可以搞出个区间DP:\(f_{i,j}\)表示区间\([i,j]\)\(i-1,j+1\)早删除,此时的最大贡献。

现在要考虑\((p_{i+1}-s_{i+2})^2\)。于是要记下\(j+1\)后面没有删的位置(即式子中的\(i+2\)),设为\(t\)。转移的时候枚举\(k\)区间内最后删除的位置,并且还要枚举左区间所对应的\(t\),记为\(v\)。这时候要保证\([k+1,v]\)的数都要比\(v\)早删。所以状态要再记个\(u\)表示\([i,u)\)中的数都不能比\(u\)早删。

于是状态记为\(f_{i,j,t,u}\)。转移方程见程序。

时间\(O(n^6)\)

发现这个时候有种情况记不了,例如\(3,1,4,2,5\)(数字表示删的顺序),其中搞到\(3\)的时候对应的\(i+2\)\(5\),搞到\(1\)的时候对应的\(i+2\)\(2\)。然而\(1\)的贡献于区间\([1,2]\)中统计,搞不到后面。但是可以发现,和\(i+2\)有关的只有\((p_{i+1}-s_{i+2})^2\),这里的\(i+1\)即区间右端点\(+1\),它是不变的。那么存在一种方案,搞到\(3\)的时候对应\(i+2\)\(2\),搞到\(1\)的时候对应\(i+2\)\(5\),尽管意义不同但是得到的值是相等的。


loj上过了,但是gmoj上没过。懒得卡常。

#pragma GCC optimize("O2")
#pragma G++ optimize("O2")
using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <climits>
#define N 75
#define ll long long
int n;
ll p[N],q[N],r[N],s[N];
ll f[N][N][N][N];
ll sqr(ll x){return x*x;}
ll w(int a,int b,int c,int d){
	return sqr(p[a]-q[b])+sqr(p[b]-r[c])+sqr(p[c]-s[d]);
}
int main(){
	scanf("%d",&n);
	for (int i=1;i<=n;++i) scanf("%lld",&p[i]);
	for (int i=1;i<=n;++i) scanf("%lld",&q[i]);
	for (int i=1;i<=n;++i) scanf("%lld",&r[i]);
	for (int i=1;i<=n;++i) scanf("%lld",&s[i]);
	for (int i=n;i>=1;--i)
		for (int j=i;j<=n;++j)
			for (int t=j+1;t<=n+1;++t)
				for (int u=i;u<=j;++u){
					ll res=LLONG_MIN;
					for (int k=u;k<=j;++k){
						ll tmp=w(i-1,k,j+1,t);
						for (int v=k+1;v<=j+1;++v)
							res=max(res,f[i][k-1][v][u>k-1?i:u]+f[k+1][j][t][v>j?k+1:v]+tmp);
					}
					f[i][j][t][u]=res;
				}
	printf("%lld\n",f[1][n][n+1][1]);
	return 0;
}
posted @ 2020-11-25 18:52  jz_597  阅读(288)  评论(2编辑  收藏  举报