逐月信息学 2024 提高组 #4
\(\color{black}\texttt{A. 转盘锁}\)
题目描述
给定一个四位转盘锁,每个转盘上都有 \(0\) 到 \(9\) 的数字。数字 \(i\) 的下一个数字是 \((i+1)\bmod 10\),上一个数字是 \((i-1)\bmod 10\)。每次你可以将一段连续的区间全部往上翻或往下翻一个数字。现在给定一个初始时的转盘,求最少需要多少次操作才能达到目标状态。
思路
首先,一个转盘锁 \(abcd\rightarrow efgh\),可以看作 \(0000\rightarrow (abcd-efgh)\bmod 10\)。所以 BFS 预处理从 \(0000\) 到其他所有状态的最短路即可。
代码
#include<bits/stdc++.h>
using namespace std;
struct Node {
vector<int> v;
int dis;
};
int T, ans;
string s, t;
queue<Node> que;
map<vector<int>, int> dist;
void Record(const vector<int> &v, int dis) {
if(dist.count(v)) {
return;
}
dist[v] = dis;
que.push({v, dis});
}
void bfs() {
Record({0, 0, 0, 0}, 0);
for(; !que.empty(); ) {
auto [v, dis] = que.front();
que.pop();
for(int i = 0; i < 4; ++i) {
for(int j = i; j < 4; ++j) {
for(int op : {-1, 1}) {
for(int k = i; k <= j; ++k) {
v[k] = (v[k] + op + 10) % 10;
}
Record(v, dis + 1);
for(int k = i; k <= j; ++k) {
v[k] = (v[k] - op + 10) % 10;
}
}
}
}
}
}
void Solve() {
cin >> s >> t;
vector<int> v = {(s[0] - t[0] + 10) % 10, (s[1] - t[1] + 10) % 10, (s[2] - t[2] + 10) % 10, (s[3] - t[3] + 10) % 10};
cout << dist[v] << "\n";
}
int main() {
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
bfs();
for(cin >> T; T--; Solve()) {
}
return 0;
}
\(\color{black}\texttt{B. 多姿多彩}\)
题目描述
定义两个长度均为 \(N\) 的字符串 \(S,T\) 的多样值 \(f(S,T)\) 为 \(\sum \limits_{i=1}^N [S_i \ne T_i]\)。
求 \(\sum \limits_{i=0}^{N-1} \sum \limits_{j=0}^{N-1} f(S\operatorname{LSH}i,S\operatorname{LSH} j)\),其中 \(S\operatorname{LSH}x\) 表示 \(S\) 循环左移 \(x\) 位的结果。
思路
首先考虑这个问题的反面:即把 \(\ne\) 变为 \(=\)。这时每对相同的字符会对答案造成 \(N\) 的贡献。所以这个的答案为 \(\sum \limits_{i=1}^{26} Ncnt_i^2\),其中 \(cnt_i\) 表示字符 \(i\) 出现次数。
然后跟 \(N^3\) 相减就是最终答案。
代码
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
int n, cnt[26];
ll ans;
string s;
int main() {
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
cin >> n >> s;
s = ' ' + s;
for(int i = 1; i <= n; ++i) {
cnt[s[i] - 'a']++;
}
for(int i = 0; i < 26; ++i) {
ans += 1ll * cnt[i] * cnt[i] * n;
}
cout << 1ll * n * n * n - ans;
return 0;
}
\(\color{black}\texttt{C. 黑白树}\)
题目描述
给定一棵树,一开始每个结点为黑色或白色。你可以执行以下操作任意次:选择一个叶子节点并将其到根节点路径上所有结点反色。问最后树上最多能有多少个黑色结点。