DTOJ3629 染色游戏(paint)

蒜头是一名画家,他希望画卷上的图案从左到右越来越美观。画卷美观度由图案美观度之和与未画区域方案数之差决定。本题要求计算蒜头能获得的最大美观度。通过动态规划和二维偏序,结合归并排序进行CDQ分治,实现复杂度为Θ(nlogn)的解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目

题目描述

蒜头是一名优秀的画家
蒜头有一张长度为 n n n的画卷,在位置 i i i上画图案会获得 a i a_i ai的美观度
蒜头是一个有追求的人,因此他希望他的画从左往右是越来越美观的,即对于任意两个画了图案的格子 l < r l < r l<r,有 a l ⩽ a r a_l \leqslant a_r alar
但蒜头发现,人们评判画卷的好坏,并不会只从画出的图案来考虑
具体来说,一张画卷的美观度,定义为所有画了图案的位置的美观度之和与在图上选择两个可以重复的位置使得两位置之间不存在画了图案的位置的方案数之差
现在,蒜头想要知道,他画出的画卷的最大美观度是多少
形式化地,一段连续的长度为 m m m的空白位置会让美观度降低 m ( m + 1 ) 2 \frac{m(m+1)}{2} 2m(m+1)

输入格式

输入的第一行是一个数 n n n,表示序列的长度
接下来一行 n n n个数,第 i i i个数表示 a i a_i ai

输出格式

输出一行表示最大美观度

样例

样例输入

输入样例1
7
1 3 2 7 3 2 4
输入样例2
7
-3 -4 -2 -2 -6 -8 -1

样例输出

输出样例1
7
输出样例2
-11

数据范围与提示

对于 100 % 100 \% 100%的数据, − 1 0 8 ⩽ a i ⩽ 1 0 8 -10^8 \leqslant a_i \leqslant 10^8 108ai108
对于子任务 1 1 1 19 19 19分, n ⩽ 20 n \leqslant 20 n20
对于子任务 2 2 2 22 22 22分, n ⩽ 5000 n \leqslant 5000 n5000
对于子任务 3 3 3 18 18 18分, n ⩽ 1 0 6 n \leqslant 10^6 n106,数据随机
对于子任务 4 4 4 41 41 41分, n ⩽ 1 0 6 n \leqslant 10^6 n106

题解

首先,我们先不考虑“对于任意两个画了图案的格子 l < r l<r l<r,有 a l ⩽ a r ​ a_l \leqslant a_r​ alar”这个条件,正常的进行DP
我们用 f i f_i fi表示只画前 i i i个并且一定画第 i i i时最大的美观度
我们先写出转移方程: f i = max ⁡ j < i { f j + a i − ( i − j − 1 ) ( i − j ) 2 } f_i=\max \limits_{j<i}\{f_j+a_i-\frac{(i-j-1)(i-j)}{2}\} fi=j<imax{fj+ai2(ij1)(ij)}
我们把 ( i − j − 1 ) ( i − j ) 2 \frac{(i-j-1)(i-j)}{2} 2(ij1)(ij)展开,得到: f j + a i − ( i − j − 1 ) ( i − j ) 2 = f j + a i − i 2 2 − j 2 2 + i j + i 2 − j 2 f_j+a_i-\frac{(i-j-1)(i-j)}{2}=f_j+a_i-\frac{i^2}{2}-\frac{j^2}{2}+ij+\frac{i}{2}-\frac{j}{2} fj+ai2(ij1)(ij)=fj+ai2i22j2+ij+2i2j
接着,我们设 j < i j<i j<i max ⁡ k < i { f k + a i − ( i − k − 1 ) ( i − k ) 2 } = f j + a i − ( i − j − 1 ) ( i − j ) 2 \max \limits_{k<i}\{f_k+a_i-\frac{(i-k-1)(i-k)}{2}\}=f_j+a_i-\frac{(i-j-1)(i-j)}{2} k<imax{fk+ai2(ik1)(ik)}=fj+ai2(ij1)(ij)
那么,我们可以得到 − f j + j 2 2 + j 2 = i j − f i + a i − i 2 2 + i 2 -f_j+\frac{j^2}{2}+\frac{j}{2}=ij-f_i+a_i-\frac{i^2}{2}+\frac{i}{2} fj+2j2+2j=ijfi+ai2i2+2i
这样,我们就可以进行斜率优化DP了
解决了DP,我们再从头来考虑一下“对于任意两个画了图案的格子 l < r l<r l<r,有 a l ⩽ a r ​ a_l \leqslant a_r​ alar”这个条件
这个东西怎么这么熟悉呢?哦!是二维偏序!
所以我们可以使用CDQ分治!
但是排序用什么算法呢?快排吗?
好像太慢了,要 Θ ( n l o g 2 n ) \Theta(nlog^2n) Θ(nlog2n)
如何优化呢?既然是CDQ分治,我们排序就也用分治嘛!我们可以使用归并排序,这样可以预处理出CDQ分治的每一层,节省时间
算了一下,复杂度是 Θ ( n l o g n ) \Theta(nlogn) Θ(nlogn)
附上代码:

#include<algorithm>
#include<cstdio>
using namespace std;
int n,q[1000010],a[1000010],ord[1000010],rk[21][1000010];
long long ans,f[1000010];
int cmp(const int &x,const int &y)
{
	return a[x]<a[y]||(a[x]==a[y]&&x<y);
}
long long Slope(int x)
{
	return 2*f[x]-1ll*x*x-x;
}
void Merge_Sort(int l,int r,int d)
{
	if(l==r){rk[d][l]=ord[l];return;}
	int mid=(l+r)>>1;
	Merge_Sort(l,mid,d+1),Merge_Sort(mid+1,r,d+1);
	int i=l,j=mid+1,rank=l-1;
	while(i<=mid&&j<=r){
		if(rk[d+1][i]<rk[d+1][j]) rk[d][++rank]=rk[d+1][i++];
		else rk[d][++rank]=rk[d+1][j++];
	}
	while(i<=mid) rk[d][++rank]=rk[d+1][i++];
	while(j<=r) rk[d][++rank]=rk[d+1][j++];
}
void CDQ_DC(int l,int r,int d)
{
	if(l==r){
		f[ord[l]]=max(f[ord[l]],a[ord[l]]-1ll*(ord[l]-1)*ord[l]/2);
		ans=max(ans,f[ord[l]]-1ll*(n-ord[l])*(n-ord[l]+1)/2);
		return;
	}
	int mid=(l+r)>>1,H=1,T=0;
	CDQ_DC(l,mid,d+1),q[H]=q[T]=0;
	for(int i=mid+1,k=l;i<=r;i++){
		int j=rk[d][i];
		while(k<=mid&&rk[d][k]<j){
			long long w=rk[d][k];
			while(H<T&&((Slope(w)-Slope(q[T]))*(q[T]-q[T-1])>=(Slope(q[T])-Slope(q[T-1]))*(w-q[T]))) T--;
			q[++T]=w,k++;
		}
		while(H<T&&(Slope(q[H+1])-Slope(q[H])>=-2ll*j*(q[H+1]-q[H]))) H++;
		if(H<=T&&H) f[j]=max(f[j],f[q[H]]+a[j]-1ll*(j-q[H]-1)*(j-q[H])/2);
		ans=max(ans,f[j]-1ll*(n-j)*(n-j+1)/2);
	}
	CDQ_DC(mid+1,r,d+1);
}
int main()
{
	freopen("paint.in","r",stdin);
	freopen("paint.out","w",stdout);
	scanf("%d",&n);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]),ord[i]=i,f[i]=-1e18;
	sort(ord+1,ord+n+1,cmp),ans=-1ll*n*(n+1)/2,Merge_Sort(1,n,0),CDQ_DC(1,n,1),printf("%lld",ans);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值