CF771E Bear and Rectangle Strips

给定一个 \(2 \times n\) 的矩阵 \(T\),你需要选出若干个不相交的子矩阵,要求每个子矩阵中所有数的和为 \(0\)。求子矩阵个数的最大值。

\(1 \leq n \leq 3 \times 10^5\)\(|t_{i,j}| \leq 10^9\)

首先我们注意到一个结论,有用的子矩阵只有 \(O(n)\) 个,考虑证明。

我们不妨考虑求前缀和,和为 \(0\) 当且仅当两个端点的前缀和相同。

接下来你发现,对于同一个前缀和的值,我们只需要取任意相邻的两个即可。

容易证明这样只会有 \(O(n)\) 个子矩阵。


接下来考虑设计 dp,记 \(d_{i,j}\) 表示第一行填到位置 \(i\),第二行填到位置 \(j\) 的最大子矩形数。

接下来我们转移有三种情况,填第一行的 \([l,r]\),填第二行的 \([l,r]\),以及填两行的 \([l,r]\)

我们发现为了保持最优解的结构,我们应该选左端点最靠右的矩形,而这是可以预处理的。

接下来你就得到了一个 \(O(n^2)\) 做法,感觉很不牛。


然后加点小优化,记忆化搜索就是对的了。

不知道为啥,很神奇。

#include<iostream>
#include<cstdio>
#include<map>
using namespace std;
long long num_1[300010],num_2[300010],sum_1[300010],sum_2[300010],sum_12[300010];
int pos1[300010],pos2[300010],pos12[300010];
map<long long,int> lst_1,lst_2,lst_12; 
map<int,int> dp[300010];
int calc(int x,int y){
	if(dp[x].find(y)!=dp[x].end()){
		return dp[x][y];
	}
	int maxn=0;
	if(x!=y){
		maxn=calc(min(x,y),min(x,y));
	}
	if(pos1[x]>pos2[y]  &&  pos1[x]!=-1){
		maxn=max(maxn,calc(pos1[x],y)+1);
	}
	if(pos1[x]<=pos2[y]  &&  pos2[y]!=-1){
		maxn=max(maxn,calc(x,pos2[y])+1);
	}
	if(x==y  &&  pos12[min(x,y)]!=-1){
		maxn=max(maxn,calc(pos12[min(x,y)],pos12[min(x,y)])+1);
	}
	dp[x][y]=maxn;
	return maxn;
}
int main(){
	int n;
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%lld",&num_1[i]);
		sum_1[i]=sum_1[i-1]+num_1[i];
	}
	for(int i=1;i<=n;i++){
		scanf("%lld",&num_2[i]);
		sum_2[i]=sum_2[i-1]+num_2[i];
	}
	for(int i=1;i<=n;i++){
		sum_12[i]=sum_12[i-1]+num_1[i]+num_2[i];
	}
	lst_1[0]=0;
	pos1[0]=-1;
	int maxn_1=-1;
	for(int i=1;i<=n;i++){
		if(lst_1.find(sum_1[i])!=lst_1.end()){
			maxn_1=max(maxn_1,lst_1[sum_1[i]]);
		}
		pos1[i]=maxn_1;
		lst_1[sum_1[i]]=i;
	}
	lst_2[0]=0;
	pos2[0]=-1;
	int maxn_2=-1;
	for(int i=1;i<=n;i++){
		if(lst_2.find(sum_2[i])!=lst_2.end()){
			maxn_2=max(maxn_2,lst_2[sum_2[i]]);
		}
		pos2[i]=maxn_2;
		lst_2[sum_2[i]]=i;
	}
	lst_12[0]=0;
	pos12[0]=-1;
	int maxn_12=-1;
	for(int i=1;i<=n;i++){
		if(lst_12.find(sum_12[i])!=lst_12.end()){
			maxn_12=max(maxn_12,lst_12[sum_12[i]]);
		}
		pos12[i]=maxn_12;
		lst_12[sum_12[i]]=i;
	}
	printf("%d",calc(n,n));
	return 0;
}
posted @ 2025-12-26 16:09  Oken喵~  阅读(3)  评论(0)    收藏  举报