A 字符串
思路:模拟题意。
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
int main() {
ios::sync_with_stdio(0); cin.tie(0), cout.tie(0);
string a;
cin >> a;
cout << a.substr(1, a.size() - 1) << a[0];
return 0;
}
B 能看见几个?
思路:模拟题意。
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
int main() {
ios::sync_with_stdio(0); cin.tie(0), cout.tie(0);
int n, m, x, y;
cin >> n >> m >> x >> y;
x--, y--;
vector<string>a(n);
for (int i = 0; i < n; i++)cin >> a[i];
int res = 0;
for (int i = x; i >= 0 && a[i][y] == '.'; i--)res++;
for (int i = x; i < n && a[i][y] == '.'; i++) res++;
for (int i = y; i >= 0 && a[x][i] == '.'; i--) res++;
for (int i = y; i < m && a[x][i] == '.'; i++) res++;
cout << res - 3 << '\n';
return 0;
}
C 最小异或和
思路:为了尝试将 AAA 划分为一个或多个非空段落,我们可以尝试在相邻元素之间的 N−1N-1N−1 个位置中选择放置“分隔符”的所有 2(N−1)2^{(N-1)}2(N−1) 种组合方式。在实现上,一种有用的方法是进行位运算的穷举搜索,其中每个是否放置分隔符的 N−1N-1N−1 个选择组合被视为 N−1N-1N−1 位二进制整数,并对应于一个介于 000(含)和 2(N−1)2^{(N-1)}2(N−1)(不含)之间的整数。
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
int main() {
ios::sync_with_stdio(0); cin.tie(0), cout.tie(0);
int n;
cin >> n;
vector<int>a(n);
for (int i = 0; i < n; i++)cin >> a[i];
int res = 2e9;
cout << (1 << 30) << '\n';
for (int i = 0; i < (1 << (n - 1)); i++) {
int tres = 0, t = 0;
for (int j = 0; j < n; j++) {
t |= a[j];
if ((1 << j)&i) {
tres ^= t;
t = 0;
}
}
tres ^= t;
res = min(res, tres);
}
cout << res << '\n';
return 0;
}
D 铺房间
思路:由于约束条件较小,其中 HW≤16HW \leq 16HW≤16,因此我们可以考虑穷举地搜索覆盖的方式。
从左上角的单元格开始,进行深度优先搜索,尝试放置一个方形的榻榻米垫子,或者一个向左或向下伸出的矩形榻榻米垫子;这样,我们可以穷举地搜索所有的覆盖方式。
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
int h, w;
int f[20][20];
int dfs(int x, int y, int a, int b) {
if (x == h + 1 && y == 1)return 1;
int tx = x, ty = y + 1;
if (ty > w) {
tx++;
ty = 1;
}
if (f[x][y]) return dfs(tx, ty, a, b);
int res = 0;
if (b) {
f[x][y] = 1;
res += dfs(tx, ty, a, b - 1);
f[x][y] = 0;
}
if (a && y + 1 <= w && f[x][y + 1] == 0) {
f[x][y] = 1;
f[x][y + 1] = 1;
res += dfs(tx, ty, a - 1, b );
f[x][y] = 0;
f[x][y + 1] = 0;
}
if (a && x + 1 <= h && f[x + 1][y] == 0) {
f[x][y] = 1;
f[x + 1][y] = 1;
res += dfs(tx, ty, a - 1, b );
f[x][y] = 0;
f[x + 1][y] = 0;
}
return res;
}
int main() {
ios::sync_with_stdio(0); cin.tie(0), cout.tie(0);
int a, b;
cin >> h >> w >> a >> b;
cout << dfs(1, 1, a, b) << '\n';
return 0;
}
E 收集
思路:同一颜色的球应该以什么顺序收集。假设有kkk个颜色为iii的球,它们的坐标为x1,x2,x3,...,xkx_1, x_2, x_3, ..., x_kx1,x2,x3,...,xk(其中x1<x2<x3<...<xkx_1 < x_2 < x_3 < ... < x_kx1<x2<x3<...<xk)。
在这里,可以证明无论前一个颜色的球收集后的位置如何,我们可以假设最后一个收集的球要么位于x1x_1x1,要么位于xkx_kxk(在经过前一个颜色的球之后,不收集当前颜色的球是没有意义的,并且在经过x1x_1x1和xkx_kxk之后,所有其他的球都已经经过)。
因此,我们可以使用以下动态规划(DP)算法解决该问题:
ldp[i]和rdp[i]ldp[i]和rdp[i]ldp[i]和rdp[i]表示完成收集所有颜色为iii的球所需的最少时间,其中ldpldpldp表示位于该颜色为iii的球的最左边(x1x_1x1),rdprdprdp表示位于最右边(xkx_kxk)。(我们假设不存在没有着色的颜色,即所有颜色都至少有一个球)
具体来说,设lll为颜色为iii的球的最小坐标,rrr为最大坐标,则在收集完颜色为i−1i-1i−1的球后,到达坐标lll所需的最少时间为:
- 如果x≤rx \leq rx≤r:你先向右移动到rrr,然后再向左移动到lll,所需时间为(r−x)+(r−l)(r-x) + (r-l)(r−x)+(r−l)
- 如果x>rx > rx>r:你只需要向左移动到lll,所需时间为r−xr-xr−x
同样地,我们可以找到从收集了颜色为i−1i-1i−1后的坐标xxx开始,到达坐标rrr所需的最少时间。
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
int main() {
ios::sync_with_stdio(0); cin.tie(0), cout.tie(0);
int n;
cin >> n;
vector<int>e[n + 1];
for (int i = 0; i < n; i++) {
int x, c;
cin >> x >> c;
e[c].push_back(x);
}
vector<int>l(n + 1, 0), r(n + 1, 0);
vector<ll>ldp(n + 1, 0), rdp(n + 1, 0);
for (int i = 1; i <= n; i++) {
sort(e[i].begin(), e[i].end());
if (e[i].size()) {
ll tl = ldp[i - 1] + abs(e[i][e[i].size() - 1] - l[i - 1]) +
abs(e[i][0] - e[i][e[i].size() - 1]);
ll tr = rdp[i - 1] + abs(e[i][e[i].size() - 1] - r[i - 1]) +
abs(e[i][0] - e[i][e[i].size() - 1]);
ldp[i] = min(tl, tr);
tl = ldp[i - 1] + abs(e[i][0] - l[i - 1]) +
abs(e[i][e[i].size() - 1] - e[i][0]);
tr = rdp[i - 1] + abs(e[i][0] - r[i - 1]) +
abs(e[i][e[i].size() - 1] - e[i][0]);
rdp[i] = min(tl, tr);
l[i] = e[i][0];
r[i] = e[i][e[i].size() - 1];
}
else {
l[i] = l[i - 1];
r[i] = r[i - 1];
ldp[i] = ldp[i - 1];
rdp[i] = rdp[i - 1];
}
}
cout << min(ldp[n] + abs(l[n]), rdp[n] + abs(r[n]));
return 0;
}
F 最短回文
思路:假设在每个顶点1和N上都放有一块棋子,并且你可以重复以下操作:“将每个棋子移动到其相邻的顶点,使用具有相同字符的边”——直到两个棋子最终靠近。
对于回文串的长度为偶数的情况,只需要找到使两个棋子到达相同顶点的最小移动次数;对于长度为奇数的回文串,只需要找到使两个棋子之间的距离恰好为1的最小移动次数。
剩下的工作就是从对应于(1,N)(1, N)(1,N)的顶点开始,在这个图上执行广度优先搜索(BFS),并检查偶数长度和奇数长度的回文串。(对于偶数长度的回文串,只需检查到达对应于(i,i)(i, i)(i,i)的顶点的最短距离,对所有iii;对于奇数长度的回文串,只需检查对应于(a,b)(a, b)(a,b)和(b,a)(b, a)(b,a)的顶点之间的最短距离,对所有边(a,b)(a, b)(a,b))。
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
int main() {
ios::sync_with_stdio(0); cin.tie(0), cout.tie(0);
int n, m;
cin >> n >> m;
vector<vector<vector<int>>>e(n, vector<vector<int>>(26));
vector<vector<int>>dis(n, vector<int>(n, -1));
queue<array<int, 2>>q;
for (int i = 0; i < n; i++) {
q.push({i, i});
dis[i][i] = 0;
}
for (int i = 0; i < m; i++) {
int u, v;
char c;
cin >> u >> v >> c;
int cc = c - 'a';
u--, v--;
if (u > v)swap(u, v);
if (dis[u][v] == -1) {
q.push({u, v});
dis[u][v] = 1;
}
e[u][cc].push_back(v);
e[v][cc].push_back(u);
}
while (q.size()) {
auto [x, y] = q.front();
q.pop();
for (int i = 0; i < 26; i++) {
for (auto j : e[x][i]) {
for (auto jj : e[y][i]) {
if (dis[min(j, jj)][max(j, jj)] == -1) {
dis[min(j, jj)][max(j, jj)] = dis[x][y] + 2;
q.push({min(j, jj), max(j, jj)});
}
}
}
}
}
cout << dis[0][n - 1];
return 0;
}
文章介绍了C++代码解决五个不同编程题目:字符串处理(A、B),动态规划(C),深度/广度优先搜索(D、F),以及最短路径(E)。涉及内容包括子串查找、区间覆盖和最短异或和计算等。
1044

被折叠的 条评论
为什么被折叠?



