P7482 题解

P7482

思路

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

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

fi,0=max(fi+1,0,fi+2,0+ai)f_{i,0}=\max (f_{i+1,0},f_{i+2,0}+a_i)

ans(i,j)=max(fi,0+fj,1,fi,1+fj,0)ans(i,j)=\max (f_{i,0}+f_{j,1},f_{i,1}+f_{j,0})

记跨过 midmid 的贡献为 ww

w=i=lmidj=mid+1rans(i,j)w=\sum_{i=l}^{mid}\sum_{j=mid+1}^{r} ans(i,j)

gi=fi,1fi,0g_i=f_{i,1}-f_{i,0}

w=i=lmidj=mid+1rmax(gi+fi,0+fj,0,gj+fi,0+fj,0)w=\sum_{i=l}^{mid}\sum_{j=mid+1}^{r} \max(g_i+f_{i,0}+f_{j,0},g_j+f_{i,0}+f_{j,0})

w=i=lmidj=mid+1rmax(gi,gj)+i=lmidfi,0×(rmid)+j=mid+1rfj,0×(midl+1)w=\sum_{i=l}^{mid}\sum_{j=mid+1}^{r} \max(g_i,g_j)+\sum_{i=l}^{mid}f_{i,0}\times (r-mid)+\sum_{j=mid+1}^r f_{j,0}\times (mid-l+1)

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

j=mid+1rmax(gi,gj)=j=mid+1r[gigj]×gi+[gi<gj]×gj\sum_{j=mid+1}^{r} \max(g_i,g_j)=\sum_{j=mid+1}^{r}[g_i\geq g_j]\times g_i+[g_i<g_j]\times g_j

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

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

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

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);
}