P7482 题解

P7482

思路

cdq 分治拆成 [l,mid](mid,r] 的贡献。

对于一个区间计算答案可以用 dp 完成。以 mid 为交界合并左右的 dp 值。设 fi,0/1 表示区间 [i,mid] 或区间 (mid,i],是否选 midmid+1 的答案。

fi,0=max(fi+1,0,fi+2,0+ai)

ans(i,j)=max(fi,0+fj,1,fi,1+fj,0)

记跨过 mid 的贡献为 w

w=i=lmidj=mid+1rans(i,j)

gi=fi,1fi,0

w=i=lmidj=mid+1rmax(gi+fi,0+fj,0,gj+fi,0+fj,0)

w=i=lmidj=mid+1rmax(gi,gj)+i=lmidfi,0×(rmid)+j=mid+1rfj,0×(midl+1)

后面两个直接做,前面的对于每个 i 拆开 max 计算。

j=mid+1rmax(gi,gj)=j=mid+1r[gigj]×gi+[gi<gj]×gj

(mid,r]gj 排序,二分 gi 的位置,记录 gj 的后缀和即可。

其余的递归 [l,mid](mid,r] 解决。

然后发现一个 sub 都没过。原因是不一定一定要选 midmid+1,将 fi,1 的定义改为区间不考虑任何限制的最大值,强行当作选 mid 位置即可。

code

int n,a[maxn],ans;
int f[maxn][2],g[maxn];
int b[maxn],len,sum[maxn];
void sovle(int l,int r){
	if(l==r){
		(ans+=a[l])%=mod;
		return ;
	}
	int mid=l+r>>1;
	f[mid][0]=0,f[mid][1]=a[mid];
	if(mid-1>=l)f[mid-1][0]=a[mid-1],f[mid-1][1]=max(a[mid-1],a[mid]);
	for(int i=mid-2;i>=l;i--){
		f[i][0]=max(f[i+1][0],f[i+2][0]+a[i]);
		f[i][1]=max(f[i+1][1],f[i+2][1]+a[i]);
	}
	f[mid+1][0]=0,f[mid+1][1]=a[mid+1];
	if(mid+2<=r)f[mid+2][0]=a[mid+2],f[mid+2][1]=max(a[mid+2],a[mid+1]);
	for(int i=mid+3;i<=r;i++){
		f[i][0]=max(f[i-1][0],f[i-2][0]+a[i]);
		f[i][1]=max(f[i-1][1],f[i-2][1]+a[i]);
	}
	int sl=0,sr=0;
	for(int i=l;i<=mid;i++)(sl+=f[i][0])%=mod;
	for(int i=mid+1;i<=r;i++)(sr+=f[i][0])%=mod;
	(ans+=sl*(r-mid)+sr*(mid-l+1))%=mod;
//	cout<<l<<" "<<r<<" "<<ans<<"\n"; 
	for(int i=l;i<=r;i++)g[i]=f[i][1]-f[i][0];
	len=0; 
	for(int i=mid+1;i<=r;i++)b[++len]=g[i];
	sort(b+1,b+len+1);sum[len+1]=0;
	for(int i=len;i>=1;i--)sum[i]=(sum[i+1]+b[i]%mod+mod)%mod;
	for(int i=l;i<=mid;i++){
		int p=upper_bound(b+1,b+len+1,g[i])-b;
		(ans+=(g[i]%mod+mod)*(p-1)+sum[p])%=mod;
//		cout<<i<<" "<<g[i]<<" "<<p<<" "<<sum[p]<<"\n";
	}
	sovle(l,mid),sovle(mid+1,r);
}
posted @   yhddd  阅读(16)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· .NET Core 中如何实现缓存的预热?
· 三行代码完成国际化适配,妙~啊~
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
点击右上角即可分享
微信分享提示