【补题】【atcoderabc434】【codeforces1067】

前缀和

https://atcoder.jp/contests/abc434/tasks/abc434_d

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
using ll=long long;
int main(){
	vector<vector<ll>>a(2025,vector<ll>(2025,0));
	vector<vector<ll>>b(2025,vector<ll>(2025,0));
	ll n;cin>>n;
	for(int i=1;i<=n;i++){
		ll u,d,l,r;cin>>u>>d>>l>>r;
		d++;r++;
		a[u][l]++;a[u][r]--;a[d][l]--;a[d][r]++;
		b[u][l]+=i;b[u][r]-=i;b[d][l]-=i;b[d][r]+=i;
		
	}for(int i=0;i<2025;i++){
		for(int j=0;j<2025;j++){
		    if(j){a[i][j]+=a[i][j-1];
			b[i][j]+=b[i][j-1];}
		}
	}for(int i=0;i<2025;i++){
		for(int j=0;j<2025;j++){
			if(i){a[i][j]+=a[i-1][j];
				b[i][j]+=b[i-1][j];}
		}
	}
	vector<ll>bk(n+1,0);
	for(int i=1;i<=2000;i++){
		for(int j=1;j<=2000;j++){
			if(a[i][j]==0){bk[0]++;}
			else if(a[i][j]==1){bk[b[i][j]]++;}//记录是第几块
		}
	}for(int i=1;i<=n;i++){
	    cout<<bk[0]+bk[i]<<'\n';
	}
	
}

核心思想:动态规划

前缀和的计算本质上是动态规划,利用已经计算好的结果来推导新的结果。

分步证明

第一步:水平方向前缀和

执行完第一个双重循环后:

复制代码
a[i][j] = 原数组第i行中,从第0列到第j列的所有元素之和

即:a[i][j] = original[i][0] + original[i][1] + ... + original[i][j]

第二步:垂直方向前缀和

现在我们要计算从 (0,0)(i,j) 的矩形区域和:

复制代码
目标:sum(0,0 → i,j) = 所有行从第0列到第j列的和之和

当执行 a[i][j] += a[i-1][j] 时:

  • 左边的 a[i][j] 是第i行从0到j列的和
  • 右边的 a[i-1][j] 是前i-1行从0到j列的总和(因为上一步已经计算了水平前缀和)

所以:

复制代码
a[i][j] = (第i行从0到j列的和) + (前i-1行从0到j列的总和)
        = 从第0行到第i行,每行从0列到j列的和之和
        = 从(0,0)到(i,j)的矩形区域和

可视化例子

假设原数组:

复制代码
1 2 3
4 5 6
7 8 9

第一步后(水平前缀和):

复制代码
1  3  6
4  9  15
7  15 24

第二步后(垂直前缀和):

复制代码
1   3   6
5   12  21  ← 1+4=5, 3+9=12, 6+15=21
12  27  45  ← 5+7=12, 12+15=27, 21+24=45

验证:a[2][2] = 45 正是原数组所有元素之和 1+2+3+4+5+6+7+8+9=45

为什么顺序很重要

如果调换两个循环的顺序(先垂直后水平),结果也是正确的,因为前缀和计算满足交换律

这种分步计算的方法比直接四重循环更高效,时间复杂度从 O(n⁴) 降到了 O(n²)。

这是一个很好的问题!让我来解释为什么树结构要减1。

dfs

https://atcoder.jp/contests/abc434/tasks/abc434_e

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
int main(){
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	int n;cin>>n;
	vector<int>x(n),r(n);
	map<int,vector<pair<int,int>>>g;
	for(int i=0;i<n;i++){
		cin>>x[i]>>r[i];
		int xp=x[i]+r[i];
		int xr=x[i]-r[i];
		g[xr].emplace_back(xp,i);
		g[xp].emplace_back(xr,i);
		//TODO
	}set<int>vis;
	auto dfs=[&](auto rc,int c,int en)->pair<int,int>{
		vis.insert(c);//标记当前坐标已访问
		int num=1;//当前联通分量的节点数
		int is=true;
		for(auto& [d,e]:g[c]){
			if(e==en)continue;
			if(vis.count(d)){//邻接点已访问,存在环,不是树
				is=false;
			}else{
				auto[n,f]=rc(rc,d,e);
				num+=n;
				is&=f;
			}
		}return make_pair(num,is);//节点数,是否是树
	};
	int ans=0;
	for(auto& [ket,_]:g){
		if(vis.count(ket))continue;
		//对每个联通分量dfs
		auto[num,is]=dfs(dfs,ket,-1);
		//是树,不同坐标=节点-1
		//是环,不同坐标=节点
		ans+=is?num-1:num;
		//TODO
	}cout<<ans<<'\n';
}

一棵树第一个点两条边,后来多一个点一条边,所以是n-1

如果有环,先最小生成树有n-1个点,后来利用其他边来涂色这个

模拟、思维

https://codeforces.com/contest/2158/problem/D

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
vector<array<int,2>>reduce(string &s){
	int n=s.size();
	vector<array<int,2>>op;
     int p=-1;
	//寻找相邻相同
	for(int i=0;i<n-1;i++){
		if(s[i]==s[i+1])p=i;//相邻字符的位置
		//TODO
	}//无相同,严格交替
	if(p==-1){
		//前3个一定是回文
		op.push_back({0,2});
		s[0]^=1;s[1]^=1;
		p=2;//现在有两位相等
	}char va=s[p+1];//块中字符值
	int l=p,r=p+1;//【l,r】中字符相等
	//向右扩展
	while(r+1<n){
		if(s[r+1]!=va)op.push_back({l,r});//字符不同,翻转
		r++;va=s[r];//翻转后这一段都变成s【r】
	}while(l){//字符不同,翻转
		if(s[l-1]!=va)op.push_back({l,r});
		l--;va=s[l];//更新当前块的值
	}
	//全1翻转变全0
	if(va=='1')op.push_back({0,n-1});
	return op;
}
void solve(){
	int n;cin>>n;
	string s,t;cin>>s>>t;
	auto ops=reduce(s);//s转到全0
	auto opt=reduce(t);//t转到全0
	//t变全0转,将全0变t
	reverse(opt.begin(),opt.end());
	int mo=ops.size()+opt.size();
	cout<<mo<<'\n';
	//s到全0,全0到t
	for(auto &[x,y]:ops){cout<<x+1<<' '<<y+1<<'\n';
	}for(auto &[x,y]:opt){cout<<x+1<<' '<<y+1<<'\n';
	}
}
int main(){
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	int t;cin>>t;
	while(t--){
		solve();
	}
}
相关推荐
roman_日积跬步-终至千里1 小时前
【模式识别与机器学习】AdaBoost算法:集成学习的基本原理与AdaBoost算法的应用
算法·机器学习·集成学习
mit6.8241 小时前
中位数贪心|前缀和_距离和ret=l+r_1
算法
一匹电信狗1 小时前
【LeetCode】栈和队列进阶题目
c++·算法·leetcode·职场和发展·stl·栈和队列
机器学习之心1 小时前
198种组合算法+优化TCN时间卷积神经网络+SHAP分析+新数据预测+多输出!深度学习可解释分析,强烈安利,粉丝必备!
深度学习·算法·shap分析·tcn时间卷积神经网络
代码游侠1 小时前
数据结构——线性表
linux·c语言·数据结构·学习·算法
吃着火锅x唱着歌1 小时前
LeetCode 3371.识别数组中的最大异常值
数据结构·算法·leetcode
元亓亓亓1 小时前
LeetCode热题100--74. 搜索二维矩阵--中等
算法·leetcode·矩阵
zzzsde1 小时前
【C++】异常:概念及使用
开发语言·c++·算法
ghie90901 小时前
ART 和SART 医学CT重建迭代重建算法
人工智能·算法·计算机视觉