ABC419题解

A. AtCoder Language

简单字符串判断题

code
#include<bits/stdc++.h>
using namespace std;
string s;
int main(){
	ios::sync_with_stdio(false);cin.tie(0);
	cin >> s;
	if(s == "red") cout << "SSS";
	else if(s == "blue") cout << "FFF";
	else if(s == "green") cout << "MMM";
	else cout << "Unknown";
} 

B. Get Min

priority_queue 模拟即可

code
#include<bits/stdc++.h>
using namespace std;
int Q;
int op,x;
priority_queue<int,vector<int>, greater<int> > q;
int main(){
	ios::sync_with_stdio(false),cin.tie(0);
	cin >> Q;
	while(Q--){
		cin >> op;
		if(op == 1){
			cin >> x;
			q.push(x);
		}
		else{
			cout << q.top() << '\n';
			q.pop();
		}
	}
} 

C. King's Summit

因为是可以走周围 8 格,所以我们的答案就是 \(\max \{\lceil\frac {maxx-minx}2\rceil,\lceil \frac {maxy-miny} 2\rceil\}\)

code
#include<bits/stdc++.h>
using namespace std;
int n,maxx,minx,maxy,miny;
int main(){
	ios::sync_with_stdio(false),cin.tie(0);
	minx = miny = 1e9 + 7;
	cin >> n;
	for(int i = 1,x,y; i <= n; ++i){
		cin >> x >> y;
		maxx = max(x,maxx);minx = min(x,minx);
		maxy = max(y,maxy);miny = min(y,miny);
	}
	cout << max((maxx+1-minx)/2,(maxy+1-miny)/2);
} 

bonus:只能走周围四格怎么办

solution

在4邻接移动下,从点 \((x_1, y_1)\) 到点 \((x_2, y_2)\) 的最小时间(即曼哈顿距离)为:

\[t = |x_1 - x_2| + |y_1 - y_2| \]

我们需要找到一个点 \((x, y)\),使得所有 \(N\) 个人移动到该点的最大曼哈顿距离最小。这个最小值就是所有人汇聚到同一个格子的最小时间。

然而曼哈顿距离有绝对值,所以我们要将其转为切比雪夫距离

关键思路

通过坐标变换:

\[u = x + y, \quad v = x - y \]

曼哈顿距离 \(|x_i - x| + |y_i - y|\) 可以表示为:

\[\max\{ |u_i - u|, |v_i - v| \} \]

因此,原问题转化为:找到点 \((u, v)\),使得:

\[\max_i \{ |u_i - u|, |v_i - v| \} \]

最小。

算法步骤

  1. 读入所有点 \((R_i, C_i)\)
  2. 计算每个点的 \(u_i = R_i + C_i\), \(v_i = R_i - C_i\)
  3. 二分答案 \(t\)(范围0到4e9)
  4. 对于二分值 \(t\),计算:

    \[L_u = \max_i (u_i - t), \quad R_u = \min_i (u_i + t) \]

    \[L_v = \max_i (v_i - t), \quad R_v = \min_i (v_i + t) \]

  5. 如果区间为空,则 \(t\) 不可行
  6. 检查是否存在整数对 \((u, v)\) 满足区间约束且 \(u\)\(v\) 同奇偶
  7. 如果存在则 \(t\) 可行,否则不可行

D. Substr Swap

这道题就是一个区间异或的题目,用树状数组维护即可

code
#include<bits/stdc++.h>
using namespace std;
const int NN = 5e5 + 8;
int n,m;
string s,t;
int a[NN],b[NN << 1];
inline int lowbit(int x){return x & (-x);}
void add(int x){
	while(x){
		a[x] ^= 1;
		x -= lowbit(x); 
	}
}
void get(){
	for(int i = n; i >= 0; --i){
		b[i] = b[i+lowbit(i)] ^ a[i];
	}
}
int main(){
	ios::sync_with_stdio(false),cin.tie(0);
	cin >> n >> m;
	cin >> s >> t;
	for(int i = 1,l,r; i <= m; ++i){
		cin >> l >> r;
		add(r);add(l-1);
	}
	get();
	for(int i = 1; i <= n; ++i){
		if(b[i]) swap(s[i-1],t[i-1]);
	}
	cout << s;
}

E. Subarray Sum Divisibility

我们首先显然可以发现一个性质,就是下标 \(mod\ m\) 相同的数,最后修改结束后的数值一定是一样的

于是我们就可以设 \(f_{i,j}\) 表示考虑了 \(\mod m == 0\sim i\) 的所有数,这些数的和为 \(j\) 的最小的修改次数。

然后我们可以对于每一组下标 \(\mod m\) 相同的数,可以线性复杂度求出全部把这些数修改为 \(0\) 的次数,然后每一次修改的数的值 \(+1\),都可以在 \(O(1)\) 的时间内求出新的答案

最后的总复杂度为 \(O(n^3)\)

code
#include<bits/stdc++.h>
using namespace std;
const int NN = 5e2 + 8;
int n,m,l;
int a[NN];
int cost[NN],cnt[NN];
int ctt[NN][NN];
int f[NN][NN];
int main(){
	memset(f,0x3f,sizeof(f));
	ios::sync_with_stdio(false),cin.tie(0);
	cin >> n >> m >> l;
	for(int i = 1; i <= n; ++i){
		cin >> a[i];
		cost[i%l] += (m-a[i]) % m;
		++cnt[i%l];
		++ctt[i%l][a[i]];
	}
	f[0][0] = cost[0];
	for(int i = 1; i < m; ++i){
		f[0][i] = f[0][i-1] + cnt[0] - ctt[0][i] * m;
	}
	for(int i = 1; i < l; ++i){
		int cst = cost[i];
		for(int j = 0; j < m; ++j){
			if(j != 0){
				cst = cst + cnt[i] - ctt[i][j] * m;
			}
			for(int k = 0; k < m; ++k){
				int x = (k + j) % m;
				f[i][x] = min(f[i][x],f[i-1][k] + cst);
			}
		} 
	}
//	for(int i = 0; i < l; ++i){
//		for(int j = 0; j < m; ++j){
//			cout << f[i][j] << ' ';
//		}
//		cout << '\n';
//	} 
	cout << f[l-1][0]; 
} 

F. All Included

AC自动机 + 状压DP

G. Count Simple Paths 2

虚树 + 暴力

posted @ 2025-08-31 21:47  ricky_lin  阅读(13)  评论(0)    收藏  举报