LGP5504题解

一切的最值问题都可以通过“我比你逊”来达到优化的目的。

考虑一个特别特别傻逼的 DP:

\[dp[n]=\max_{i=1}^{n-1}dp[i]+cost(i+1,n) \]

\(cost(l,r)\) 是在 \(l,r\) 中寻找一种颜色满足题目中的要求。

这玩意儿看上去很难搞,不太能写成多项式之类的东西。所以优化的话只能考虑决策单调性了。

然后你发现 \(cost\) 并不满足四边形不等式,hack:\(2,2,3,2\)

那么我们只能先从转移入手,去掉除了决策单调性之外别的无用转移。

稍微观察一下可以发现,如果 \(col[l]\neq col[r]\),那么 \(cost(l,r)\) 是不如 \(cost(l,l)+cost(l+1,r)\) 的。

也就是说,转移方程可以写成这样:

\[dp[n]=\max_{i=1}^{n-1}dp[i]+cost(i+1,pre[i+1][col[n]])+cost(pre[i+1][col[n]]+1,n) \]

然后再观察观察,可以写成这样:

\[dp[n]=\max_{i=1,col[i+1]=col[n]}^{n-1}dp[i]+cost(i+1,n) \]

来考虑这个 \(cost\) 应该怎么决策单调性。

容易发现这个 \(cost\) 应该只计算 \(col[l]\)\(col[r]\) 的颜色。原因很简单,如果不计算这种颜色让别的颜色占了上风,还不如开两个区间。

然后我们发现,现在的 \(cost\) 似乎可以写成和前缀和相关的多项式了。

\[dp[n]=\sum_{i=1,col[n]=col[i]}^{n} dp[i-1]+(sum[n]-sum[i]+1)^2 \]

然后就可以愉快的使用斜率优化了。但是因为我不会写单调队列所以写了颗李超树上去。

#include<cstdio>
typedef long long ll;
const int N=1e4+5,M=1e5+5;
int n,tot,a[M],t[M],ls[M],rs[M],sum[M];ll dp[M];
int cnt[N],root[N];
struct line{
	int k;ll b;
	line(const int&k=0,const ll&b=0):k(k),b(b){}
	inline ll operator()(const int&x)const{
		return 1ll*k*x+b;
	}
}l[M];
inline void swap(int&a,int&b){
	int c=a;a=b;b=c;
}
inline ll max(const ll&a,const ll&b){
	return a>b?a:b;
}
inline void ins(int&u,int id,const int&L=1,const int&R=n){
	if(!u)return void(t[u=++tot]=id);
	const int&mid=L+R>>1;if(l[id](mid)>l[t[u]](mid))swap(id,t[u]);
	if(L==R||(l[id](L)<=l[t[u]](L)&&l[id](R)<=l[t[u]](R)))return;
	l[id](L)>l[t[u]](L)?ins(ls[u],id,L,mid):ins(rs[u],id,mid+1,R);
}
inline ll qry(const int&u,const int&x,const int&L=1,const int&R=n){
	if(!u)return 0;if(L==R)return l[t[u]](x);const int&mid=L+R>>1;
	return max(l[t[u]](x),x<=mid?qry(ls[u],x,L,mid):qry(rs[u],x,mid+1,R));
}
signed main(){
	scanf("%d",&n);for(int i=1;i<=n;++i)scanf("%d",a+i),sum[i]=++cnt[a[i]];
	for(int i=1;i<=n;++i){
		l[i]=line(-2ll*a[i]*(sum[i]-1),dp[i-1]+1ll*a[i]*(sum[i]-1)*(sum[i]-1));ins(root[a[i]],i);
		dp[i]=qry(root[a[i]],sum[i])+1ll*a[i]*sum[i]*sum[i];
	}
	printf("%lld",dp[n]);
}
posted @ 2022-04-15 15:41  Prean  阅读(27)  评论(0编辑  收藏  举报
var canShowAdsense=function(){return !!0};