ABC437 题解

A. Feet

codes
#include<bits/stdc++.h>
using namespace std;
int main(){
	ios::sync_with_stdio(false),cin.tie(0);
	long long a,b;
	cin >> a >> b;
	cout << a * 12 + b;
} 

B. Tombola

code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int H,W,N;
int a[100][100];
int row[200];
int cnt[200];
int main(){
	ios::sync_with_stdio(false),cin.tie(0);
	cin >> H >> W >> N;
	for(int i = 1; i <= H; ++i){
		for(int j = 1; j <= W; ++j){
			cin >> a[i][j];
			row[a[i][j]] = i;
		}
	}
	
	for(int i = 1; i <= N; ++i){
		int x;
		cin >> x;
		++cnt[row[x]];
	}
	
	int ans = 0;
	for(int i = 1; i <= H; ++i) ans = max(ans, cnt[i]);
	cout << ans;
} 

C. Reindeer and Sleigh 2

贪心题,我们首先假设所有人都推车,那么一个人从推车变为坐车的代价即为 \(W_i+P_i\)

我们要让坐车的人更多,那么就按照 \(W_i+P_i\) 从小到大排序之后选取即可

code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
struct Peo{
	ll w,p;
	bool operator < (const Peo &x)const{
		return w + p < x.w + x.p;
	}
};
void solve(){
	int n;
	cin >> n;
	vector<Peo> a;a.resize(n);
	for(int i = 0; i < n; ++i){
		int w,p;
		cin >> w >> p;
		a[i] = {w,p};
	}
	sort(a.begin(),a.end());
	int l = 0, r = n;
	ll ans = 0,cnt = 0;
	for(; l < r; ++l){
		while(ans < a[l].w && l < r){
			ans += a[--r].p;
		}
		if(l == r) break;
		ans -= a[l].w;
		++cnt;
	}
	cout << cnt << '\n';
}
int main(){
	int T;
	cin >> T;
	while(T--){
		solve();
	}
}

D. Sum of Differences

双指针即可

code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int NN = 3e5 + 8;
const ll MOD = 998244353;
int n,m;
ll a[NN],b[NN];
ll pre[NN];
int main(){
	ios::sync_with_stdio(false),cin.tie(0); 
	cin >> n >> m;
	ll ans = 0;
	for(int i = 1; i <= n; ++i) cin >> a[i];
	for(int i = 1; i <= m; ++i) cin >> b[i];
	sort(a+1,a+1+n);sort(b+1,b+1+m);
	for(int i = 1; i <= m; ++i) pre[i] = pre[i-1] + b[i];
	for(int i = 1,j = 1; i <= n; ++i){
		while(a[i] > b[j] && j <= m) ++j;
		ans = ans + (a[i] * (j-1) - pre[j-1]) + (pre[m] - pre[j-1] - a[i] * (m - j + 1));
		ans %= MOD;
//		cout << "j:" << j << endl;
//		cout << (a[i] * (j-1) - pre[j-1]) << "+" << pre[m] - pre[j-1] - a[i] * (n - j + 1) << "=" << ans << endl;
	}
	cout << ans;
}

E. Sort Arrays

这道题实现上比较复杂,我们首先需要构造类似于字典序的东西,然后对于每个集合,我们把集合挂在字典树上,最后按字典序从小到大输出即可。

code
#include<bits/stdc++.h>
using namespace std;
const int NN = 3e5 + 8; 
struct Edge{
	int num,v;
	bool operator < (const Edge &x)const{
		assert(num != x.num);
		return num < x.num; 
	}
};
struct Node{
	map<int,int> num;
	vector<Edge> e;
	vector<int> node;
}tree[NN];
int id[NN];
int cnte,cntn;
void dfs(int u){
	for(auto i : tree[u].node) cout << i << " ";
	for(auto i : tree[u].e){
		dfs(i.v);
	}
}
int main(){
	ios::sync_with_stdio(false),cin.tie(0);
	int n;
	cin >> n;
	id[0] = 0;
	for(int i = 1; i <= n; ++i){
		int x,y;
		cin >> x >> y;
		int u = id[x];
		if(tree[u].num.find(y) == tree[u].num.end()){
			++cntn;
			tree[u].num[y] = tree[u].e.size();
			tree[u].e.push_back({y,cntn});
		}
		int E = tree[u].num[y];
		int v = tree[u].e[E].v;
		id[i] = v;
		tree[v].node.push_back(i);
	}
	for(int i = 0; i <= cntn; ++i){
		sort(tree[i].e.begin(),tree[i].e.end());
	}
	dfs(0);
	return 0;
}

F. Manhattan Christmas Tree 2

6,不好好读题导致的,求最大值读成了求和TAT

会MLE,没测试正确性的求和 code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int NN = 2e5 + 8;
int N,Q;
ll pre[NN][NN << 2];
ll cnt[NN][NN << 2];
int scx[NN << 1], scy[NN << 1];
int lenx,leny;
ll ans[NN];
inline ll lowbit(ll x){return x & (-x);}
void add_pre(int x,int y,ll num){
	while(x <= N){
		while(y <= lenx){
			pre[x][y] += num;
			y += lowbit(y);
		}
		x += lowbit(x);
	}
}
void add_cnt(int x,int y,ll num){
	while(x <= N){
		while(y <= lenx){
			cnt[x][y] += num;
			y += lowbit(y);
		}
		x += lowbit(x);
	}
}
ll ask_pre(int x,int y){
	ll res = 0;
	while(x){
		while(y){
			res += pre[x][y];
			y -= lowbit(y);
		}
		x -= lowbit(x);
	}
	return res;
}
ll ask_cnt(int x,int y){
	ll res = 0;
	while(x <= N){
		while(y <= lenx){
			res += cnt[x][y];
			y -= lowbit(y);
		}
		x -= lowbit(x);
	}
	return res;
}

struct Pos{
	ll x,y;
}a[NN];
struct Query{
	int op;
	ll i,L,R,x,y;
	void read(){
		cin >> op;
		if(op == 1)
			cin >> i >> x >> y;
		else
			cin >> L >> R >> x >> y;
		scx[++lenx] = x; scy[++leny] = y;
	}
}q[NN];
int main(){
	ios::sync_with_stdio(false),cin.tie(0);
	cin >> N >> Q;
	for(int i = 1; i <= N; ++i){
		cin >> a[i].x >> a[i].y;
		scx[++lenx] = a[i].x;
		scy[++leny] = a[i].y;
	}
	for(int i = 1; i <= Q; ++i)
		q[i].read();
	
	sort(scx+1,scx+1+lenx); lenx = unique(scx+1,scx+1+lenx) - scx - 1;
	sort(scy+1,scy+1+leny); leny = unique(scy+1,scy+1+leny) - scy - 1;
	
	for(int i = 1; i <= N; ++i){
		int posx = lower_bound(scx+1,scx+1+lenx,a[i].x) - scx;
		add_pre(i,posx,a[i].x);
		add_cnt(i,posx,1);
	}
	for(int t = 1; t <= Q; ++t){
		if(q[t].op == 1){
			int i = q[t].i;
			int posx = lower_bound(scx+1,scx+1+lenx,a[i].x) - scx;
			add_pre(i,posx,-a[i].x);
			add_cnt(i,posx,-1);
			a[i].x = q[t].x;
			posx = lower_bound(scx+1,scx+1+lenx,a[i].x) - scx;
			add_pre(i,posx,a[i].x);
			add_cnt(i,posx,1);
		}
		else{
			int L = q[t].L, R = q[t].R;
			int posx = lower_bound(scx+1,scx+1+lenx,q[t].x) - scx;
			ll Pre_sum = ask_pre(R,posx) - ask_pre(L-1,posx);
			ll Suf_sum = ask_pre(R,lenx) - ask_pre(L-1,lenx) - Pre_sum;
			ll Pre_cnt = ask_cnt(R,posx) - ask_cnt(L-1,posx);
			ll Suf_cnt = (R-L+1) - Pre_cnt;
			ans[t] = (q[t].x * Pre_cnt - Pre_sum) + (Suf_sum - q[t].x * Suf_cnt);
		}
	}
	for(int i = 1; i <= Q; ++i) cout << ans[i] << "\n";
} 

很板子的东西就是我们把曼哈顿距离转化为切比雪夫距离 \((x+y,x-y)\)

\(\max\{|x+y-(X+Y)|,|x-y-(X-Y)|\}\)

求距离就从原本的两个绝对值相加,变成了 两个绝对值的 \(max\)

这样我们就只需要维护一个区间的所有横纵坐标的 最大值和最小值 即可

(感觉本质上就是 为了维护 \(\max\{(x-X)+(y-Y),(x-X)-(y-Y),-(x-X)+(y-Y),-(x-X)-(y-Y)\}\) 然后进行的对应维护)

code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int NN = 2e5 + 8;
int N,Q;
ll x[NN],y[NN];
struct Node{
	ll x,y;
};
Node Min(Node &A,Node &B){
	return {min(A.x,B.x),min(A.y,B.y)};
}
Node Max(Node &A,Node &B){
	return {max(A.x,B.x),max(A.y,B.y)};
}
struct Seg{
	int l,r;
	Node minn,maxn;
	#define l(x) tree[x].l
	#define r(x) tree[x].r
	#define ls(x) (x << 1)
	#define rs(x) (x << 1 | 1)
	#define minn(x) tree[x].minn
	#define maxn(x) tree[x].maxn
}tree[NN << 2];
void pushup(int x){
	minn(x) = Min(minn(ls(x)),minn(rs(x)));
	maxn(x) = {max(maxn(ls(x)).x,maxn(rs(x)).x),max(maxn(ls(x)).y,maxn(rs(x)).y)};
}
void build(int x,int l,int r){
	l(x) = l; r(x) = r;
	if(l == r){
		minn(x) = maxn(x) = {::x[l]+y[l],::x[l]-y[l]}; 
		return;
	}
	int mid = (l + r) / 2;
	build(ls(x),l,mid);
	build(rs(x),mid+1,r);
	pushup(x);
}
void modify(int x,int pos, Node num){
	if(l(x) == pos && pos == r(x)){
		maxn(x) = minn(x) = num;
		return;
	}
	int mid = (l(x) + r(x)) / 2;
	if(pos <= mid) modify(ls(x),pos,num);
	else modify(rs(x),pos,num);
	pushup(x);
}
pair<Node,Node> query(int x,int l,int r){
	if(l <= l(x) && r(x) <= r) return make_pair(minn(x),maxn(x));
	int mid = (l(x) + r(x)) / 2;
	pair<Node,Node> res; bool vis = 0;
	if(l <= mid) vis = 1, res = query(ls(x),l,r);
	if(mid + 1 <= r){
		pair<Node,Node> resr = query(rs(x),l,r);
		if(vis) res = make_pair(Min(res.first,resr.first),Max(res.second,resr.second));
		else res = resr; 
	}
	return res;
}
int main(){
	ios::sync_with_stdio(false),cin.tie(0);
	cin >> N >> Q;
	for(int i = 1; i <= N; ++i)
		cin >> x[i] >> y[i];
	
	build(1,1,N);
	while(Q--){
		int op;
		cin >> op;
		if(op == 1){
			ll i,x,y;
			cin >> i >> x >> y;
			modify(1,i,{x+y,x-y});
		}
		else{
			ll L,R,x,y;
			cin >> L >> R >> x >> y;
			pair<Node,Node> res = query(1,L,R);
			ll X = x + y, Y = x - y; 
			cout << max(max(abs(res.first.x-X),
							abs(res.first.y-Y)),
						max(abs(res.second.x-X),
							abs(res.second.y-Y))) << endl;
		}
	} 
} 

G. Colorful Christmas Tree

posted @ 2025-12-23 12:06  ricky_lin  阅读(5)  评论(0)    收藏  举报