题目链接
https://ac.nowcoder.com/acm/contest/53366
A.小d和答案修改
字母的大小写的 ASCII 码相差32。
#include <bits/stdc++.h>
int main() {
std::string str;
std::cin >> str;
for (int i = 0; i < str.size(); i ++ ) {
if(str[i] <= 'z' && str[i] >= 'a') {
std::cout << char(str[i] - 32);
} else {
std::cout << char(str[i] + 32);
}
}
return 0;
}
B. 小d和图片压缩
按照题目进行模拟。
#include <bits/stdc++.h>
const int N = 10010;
int a[N][N];
std::vector<int> v[N];
int main() {
int n,m;
std::cin >> n >> m;
for (int i = 1; i <= n; i ++ ) {
for (int j = 1 ; j <= m ; j ++ ) {
std::cin >> a[i][j];
}
}
int idx = 1;
for (int i = 1; i <= n; i += 2, idx ++ ) {
for (int j = 1 ; j <= m - 1; j += 2 ) {
int u = (a[i][j] + a[i][j+1] + a[i+1][j] + a[i+1][j+1]) / 4;
v[idx].push_back(u);
}
}
for (int i = 1; i < idx; i ++ ) {
for (int j = 0; j < v[i].size(); j ++ ) {
std::cout << v[i][j] << " ";
}
std::cout << "\n";
}
return 0;
}
C.小d和超级泡泡堂
用 bfs 从开始位置遍历,记录经过杂草的数量
#include <bits/stdc++.h>
int n,m;
int ans = 0;
char c[1010][1010];
bool st[1010][1010];
int dx[] = {1,-1,0,0}, dy[] = {0,0,-1,1};
void bfs(int stx,int sty) {
std::queue<std::pair<int,int>> q;
q.push({stx,sty});
while(q.size()) {
auto t = q.front();
q.pop();
if(st[t.first][t.second]) continue;
st[t.first][t.second] = true;
for (int i = 0; i < 4; i ++ ) {
int x = t.first + dx[i];
int y = t.second + dy[i];
if(x > n || x < 0 || y > m || y < 0) continue;
else {
if(c[x][y] == '.') {
q.push({x,y});
} else if(c[x][y] == '!') {
ans ++ ;
q.push({x,y});
c[x][y] = '.';
}
}
}
}
return ;
}
int main() {
std::cin >> n >> m;
int stx, sty;
for (int i = 1; i <= n; i ++ ) {
for (int j = 1; j <= m; j ++ ) {
std::cin >> c[i][j];
if(c[i][j] == '@') {
stx = i, sty = j;
}
}
}
bfs(stx,sty);
std::cout << ans << "\n";
return 0;
}
D.小d和孤独的区间
假设某个 1 的左侧连续 0 的个数为 a,右侧连续 0 的个数为 b。
那么包含这个 1 且和为 1 的区间总数为 (a + 1) * (b + 1)。
将所有 1 的位置记录,并处理即可得到答案,最左侧和最右侧增加两个1方便计算。
#include <bits/stdc++.h>
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int n;
std::cin >> n;
std::vector<long long> a;
a.push_back(0);
for (int i = 0; i < n; i ++ ) {
int u;
std::cin >> u;
if(u == 1) {
a.push_back(i+1);
}
}
a.push_back(n+1);
long long ans = 0;
for (int i = 1; i < a.size() - 1; i ++ ) {
ans += (a[i] - a[i-1]) * (a[i+1] - a[i]);
}
std::cout << ans << "\n";
return 0;
}
E.小d的博弈
首先进行打表,观察规律。
#include <bits/stdc++.h>
int dp[100][100];
int dfs(int x,int y) {
if(x > y) std::swap(x,y);
if(dp[x][y] != 0) return dp[x][y];
for (int i = 1; i <= x; i ++ ) {
if(i == x - i) continue;
if(dfs(std::min(i,x-i),y) == -1) {
dp[x][y] = 1;
return 1;
}
}
for (int i = 1; i <= y; i ++ ) {
if(i == y - i) continue;
if(dfs(x,std::min(i,y-i)) == -1) {
dp[x][y] = 1;
return 1;
}
}
return -1;
}
int main() {
int n;
std::cin >> n;
for (int i = 1; i <= n; i ++ ) {
for (int j = 1; j <= n; j ++ ) {
std::cout << ((dfs(i,j) == 1) ? 'o' : 'x');
}
std::cout << "\n";
}
return 0;
}
输入 n=30,打表结果如下:
可以观察到当横纵坐标 + 1 的二进制位数相同时 Bob 赢,否则 Alice 赢 。
#include <bits/stdc++.h>
int GetLength(int u) {
int res = 0;
while (u) {
u /= 2;
res ++;
}
return res;
}
void solve() {
int n,m;
std::cin >> n >> m;
if(GetLength(n + 1) == GetLength(m + 1)) {
puts("Bob");
} else {
puts("Alice");
}
return ;
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int t;
std::cin >> t;
while(t -- ) {
solve();
}
return 0;
}
E.小d和送外卖
用 siz[root] 表示以 root 为根的子树中有多少订单数。
用 dp[root][i] 表示以 root 为根的子树中,选择 j 个订单取消,能够节省多少距离。
花费最少 = 总花费 - 最大节省距离
花费 = (子树中的订单数 - 1) * 2
状态转移方程为:
\(temp[i + j] = max(temp[i + j], dp[u][i] + dp[to][j] + 2 * (j && j == siz[to]));\)
如:
由于后续的状态会用到原先的状态,所以不能一开始就更新,用 temp 存储更新的值,类似于背包的滚动数组。temp[i + j]:表示当前子树删掉 i + j 个订单的最大节省距离
dp[u][i]:表示在以 u 为根的树中删掉 i 个订单(由于是从前向后扫描,所以只删掉前几个树中的订单)
dp[to][j]:表示删除以 to 为根的子树中 j 个订单
2 * (j && j == siz[to]:若把 to 子树的所有订单都删除,那么即可把 u -> to 的边删掉
#include <bits/stdc++.h>
typedef long long ll;
const int N = 1e5+10;
int n,m;
int st[N];
int ans = -2;
int siz[N],dp[N][55];
std::vector<int> e[N];
void dfs1(int u,int fa) {
for (int i = 0; i < e[u].size(); i ++ ) {
int to = e[u][i];
if(to == fa) continue;
dfs1(to, u);
siz[u] += siz[to];
}
}
void dfs2(int u,int fa) {
ans += 2ll * (siz[u] > 0);
for (int k = 0; k < e[u].size(); k ++ ) {
int to = e[u][k];
if(to == fa) continue;
dfs2(to, u);
std::vector<int> temp(m + 10);
for (int i = 0 ; i <= std::min(m, siz[u]); i ++ ) {
for (int j = 0 ; j <= std::min(m, siz[to]); j ++ ) {
if(i + j <= m) {
temp[i + j] = std::max(temp[i + j], dp[u][i] + dp[to][j] + 2 * (j && j == siz[to]));
}
}
}
for (int i = 0 ; i <= std::min(m, siz[u]); i ++ ) dp[u][i] = temp[i];
}
return ;
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cin >> n >> m;
for (int i = 1; i <= n - 1; i ++ ) {
int a,b;
std::cin >> a >> b;
e[a].push_back(b);
e[b].push_back(a);
}
int k;
std::cin >> k;
for (int i = 1; i <= k; i ++ ) {
int b;
std::cin >> b;
siz[b] ++ ;
}
dfs1(1,-1);
dfs2(1,-1);
ll res = 0;
for (int i = 0; i <= m; i ++ ) res = std::max(res, (ll)dp[1][i]);
std::cout << ans - res << "\n";
return 0;
}
参考
[1] 小白月赛 70 比赛题目讲解