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)类似

问最大的贡献和。

(nle 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
",f[1][n][n+1][1]);
	return 0;
}
原文地址:https://www.cnblogs.com/jz-597/p/14037804.html