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)\) 的最小时间(即曼哈顿距离)为:
我们需要找到一个点 \((x, y)\),使得所有 \(N\) 个人移动到该点的最大曼哈顿距离最小。这个最小值就是所有人汇聚到同一个格子的最小时间。
然而曼哈顿距离有绝对值,所以我们要将其转为切比雪夫距离
关键思路
通过坐标变换:
曼哈顿距离 \(|x_i - x| + |y_i - y|\) 可以表示为:
因此,原问题转化为:找到点 \((u, v)\),使得:
最小。
算法步骤
- 读入所有点 \((R_i, C_i)\)
- 计算每个点的 \(u_i = R_i + C_i\), \(v_i = R_i - C_i\)
- 二分答案 \(t\)(范围0到4e9)
- 对于二分值 \(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) \]
- 如果区间为空,则 \(t\) 不可行
- 检查是否存在整数对 \((u, v)\) 满足区间约束且 \(u\) 和 \(v\) 同奇偶
- 如果存在则 \(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
虚树 + 暴力
本文来自博客园,作者:ricky_lin,转载请注明原文链接:https://www.cnblogs.com/rickylin/p/19067391/ABC419

浙公网安备 33010602011771号