专栏文章

【题解】P10299 [CCC 2024 S5] Chocolate Bar Partition

P10299题解参与者 4已保存评论 5

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
5 条
当前快照
1 份
快照标识符
@mino1fmc
此快照首次捕获于
2025/12/02 05:33
3 个月前
此快照最后确认于
2025/12/02 05:33
3 个月前
查看原文

题意

给定一个 2×N2\times N 的矩阵 aa,将其分成若干联通块,每块的平均数均相等,求最多分成几块。

解法

平均数不方便直接处理,考虑先将其转化。注意到每一块的平均数均等于整个矩阵的平均数,于是可以将每个元素减去整个矩阵的平均数,考虑到精度原因,将其再乘上 2N2N,此时问题转化为每块的元素和为 00。设 sumi,j=k=1jai,k\displaystyle sum_{i,j}=\sum_{k=1}^ja_{i,k}
考虑用动态规划来解决问题,设 fi,j,k,0/1f_{i,j,k,0/1} 为第 ii 列,其中第 11 列的块的和为 jj,第 22 列为 kk,这两列是否在同一块中,转移方程略,但是时间复杂度爆炸。
考虑优化,发现有两个块且两个块的和均不等于 00 的状态是没必要的,因为我们可以等到有一个块和为 00 时再来更新。故设 fi,jf_{i,j} 为枚举到第 jj 列,此时第 ii 行的块和为 00,另一行的块和不确定,最多分成的块数。
考虑转移,进行分类讨论:
  1. 将第 11 和第 22 行的元素都放进同一个块中,有 fi,jmax(f0,j1,f1,j1)f_{i,j}\leftarrow\max(f_{0,j-1},f_{1,j-1})
  2. 只在第 ii 行中找到一个和为 00 的块,当块 (k,j](k,j] 满足和为 00 时有 sumi,j=sumi,ksum_{i,j}=sum_{i,k},由情况 11 的式子可知 fif_{i} 单调不降,所以设 pos=maxk=0j1k[sumi,j=sumi,k]pos=\displaystyle\max_{k=0}^{j-1}k[sum_{i,j}=sum_{i,k}],有 fi,jfi,pos+1f_{i,j}\leftarrow f_{i,pos}+1
  3. 在第 ii 行(第 jj 列及以前)和另一行(第 jj 列之前)找一个横跨两行且和为 00 的块,由于选了这个块以后以前的所有元素均已固定,所以假设这个块包含了前面的所有元素,设 kk 为满足条件的块在另一行最右侧的位置的左边,则有 sumi,j+sumi1,k=0sum_{i,j}+sum_{i\oplus1,k}=0,同上知 fi1f_{i\oplus1} 单调不降,所以设 pos=maxk=0j1k[sumi,j=sumi1,k]pos=\displaystyle\max_{k=0}^{j-1}k[sum_{i,j}=-sum_{i\oplus1,k}],有 fi,jfi1,pos+1f_{i,j}\leftarrow f_{i\oplus1,pos}+1
  4. 特殊情况,当有 sum0,j+sum1,j=0sum_{0,j}+sum_{1,j}=0 时,另一行那个不确定和是否为 00 的块的和为 00,此时有 f0,j,f1,jmax(f0,j,f1,j)+1f_{0,j},f_{1,j}\gets\max(f_{0,j},f_{1,j})+1
最终答案为 maxi{0,1}maxj=1Nfi,j\displaystyle\max_{i\in\{0,1\}}\max_{j=1}^Nf_{i,j}

实现

pre1jpre1_{j} 为情况 22jjpospos,设 pre2jpre2_{j} 为情况 33jjpospos,用 unordered_map 维护即可。
时间复杂度 O(N)O(N),可以通过此题。

代码

CPP
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e5+5;
int a[2][N],sum[2][N],pre1[2][N],pre2[2][N],f[2][N],g[N];
unordered_map<int,int>flg;
signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
	int n,s=0;
	cin>>n;
	for(int i:{0,1})
	for(int j=1;j<=n;j++)
		cin>>a[i][j],s+=a[i][j],a[i][j]*=n<<1;
	for(int i:{0,1})
	for(int j=1;j<=n;j++)
		sum[i][j]=sum[i][j-1]+a[i][j]-s;
	for(int i:{0,1})
	{
		flg[0]=1;
		for(int j=1;j<=n;j++)
		{
			pre1[i][j]=flg[sum[i][j]]-1;
			flg[sum[i][j]]=j+1;
		}
		flg.clear();
	}
	for(int i:{0,1})
	{
		flg[0]=1;
		for(int j=1;j<=n;j++)
		{
			pre2[i][j]=flg[-sum[i][j]]-1;
			flg[sum[i^1][j]]=j+1;
		}
		flg.clear();
	}
	int ans=0;
	for(int j=1;j<=n;j++)
	{
		for(int i:{0,1})
		{
			f[i][j]=max(f[0][j-1],f[1][j-1]);
			if(pre1[i][j]!=-1)f[i][j]=max(f[i][j],f[i][pre1[i][j]]+1);
			if(pre2[i][j]!=-1)f[i][j]=max(f[i][j],f[i^1][pre2[i][j]]+1);
		}
		if(sum[0][j]+sum[1][j]==0)f[0][j]=f[1][j]=max(f[0][j],f[1][j])+1;
		ans=max(f[0][j],f[1][j]);
	}
	cout<<ans;
	return 0;
}

评论

5 条评论,欢迎与作者交流。

正在加载评论...