CF1580D Subsequence 题解

Codeforces
Luogu

Description..

给定一个序列 \(\{a_i\}\),选出长度为 \(k\) 的子序列 \(\{a_{b_i}\}\),使得下式最大。

\[\sum_{i=1}^mma_{b_i}-\sum_{i=1}^m\sum_{j=1}^mF(b_i,b_j) \]

定义 \(F(i,j)\) 表示 \([\min(i,j),\max(i,j)]\) 中最小值。

Solution.

式子可以化成

\[\sum_{i=1}^m(m-1)c_i-2\sum_{i=1}^m\sum_{j=i+1}^mf(b_i,b_j)\\ \]

前半段显然直接计算就行了,主要是后半段。
发现有一个 \(\min\),可以考虑按最值分治,分治处理两端然后合并。
考虑一个 \(dp_{id,j}\) 表示 \(id\) 这个区间选 \(j\) 个数的最大价值。
看似总复杂度是 \(O(n^2m)\) 的,但是考虑树上背包复杂度,发现是 \(O(nm)\) 的。
然后就做完了。

本质上就是笛卡尔树两点距离和,可以考虑背包

Coding.

点击查看代码
//是啊,你就是那只鬼了,所以被你碰到以后,就轮到我变成鬼了{{{
#include<bits/stdc++.h>
using namespace std;typedef long long ll;
template<typename T>inline void read(T &x)
{
	x=0;char c=getchar(),f=0;
	for(;c<48||c>57;c=getchar()) if(!(c^45)) f=1;
	for(;c>=48&&c<=57;c=getchar()) x=(x<<1)+(x<<3)+(c^48);
	f?x=-x:x;
}
template<typename T,typename...L>inline void read(T &x,L&...l) {read(x),read(l...);}//}}}
const int N=4005;int n,m,id;ll a[N],dp[N][N];
inline void upd(ll &a,ll b) {a<b?a=b:a;}
inline int solve(int l,int r)
{
	if(l>r) return 0;else if(l==r) return dp[++id][1]=a[l]*(m-1),id;
	int wh=l;for(int i=l+1;i<=r;i++) if(a[i]<a[wh]) wh=i;
	int ld=solve(l,wh-1),rd=solve(wh+1,r),lz=wh-l,rz=r-wh;id++;
	for(int i=0;i<=lz;i++) for(int j=0;j<=rz;j++)
	{
		upd(dp[id][i+j],dp[ld][i]+dp[rd][j]-2ll*i*j*a[wh]);
		upd(dp[id][i+j+1],dp[ld][i]+dp[rd][j]+(m-1)*a[wh]-2ll*(i*j+i+j)*a[wh]);
	}return id;
}
int main()
{
	read(n,m);for(int i=1;i<=n;i++) read(a[i]);
	return printf("%lld\n",dp[solve(1,n)][m]),0;
}
posted @ 2021-10-20 12:42  Peal_Frog  阅读(24)  评论(0编辑  收藏  举报