2025年四川省赛
https://codeforces.com/gym/105949
H. Hututu
题意:在网格中,从 (x, y) 移动到 (X, Y) 。移动操作为:\((x\pm1,y\pm1),(x\pm2,y\pm2),(x\pm1,y\pm2),(x\pm2,y\pm1)\),求最小步数。
题解:尽可能走最远,也就是 x 轴和 y 轴走 2 步。\(c=min(\lceil\frac{abs(X-x)}{2}\rceil,\lceil\frac{abs(Y-y)}{2}\rceil)\) ,走 c 步之后,有一个轴是已经到达了,继续走另外一个轴。
但是如果起始就有一个轴达到了,另外一个轴没有达到,那么步数至少为 2. 因为没有方法可以垂直移动或者水平移动。
void slove() {
int a, b, x, y; cin >> a >> b >> x >> y;
if (a == x && b == y) {
cout << 0 << endl;
return;
}
int res1 = (abs(a - x) + 1) / 2, res2 = (abs(b - y) + 1) / 2;
int c = min(res1, res2);
int X = max(0, abs(a - x) - c * 2), Y = max(0, abs(b - y) - c * 2);
c += (X + 1) / 2 + (Y + 1) / 2;
if (abs(a - x) == 0 || abs(b - y) == 0) {
c = max(2, c);
}
cout << c << endl;
}
I. Essentially Different Suffixe
题意:给定 n 个字符串,求有多少个不同的后缀。
题解:每个字符串的后缀记录在 trie 中。
struct Node {
Node* son[26];
int cnt;
Node() {
for (int i = 0; i < 26; i++) {
son[i] = nullptr;
}
cnt = 0;
}
};
void slove() {
int n; cin >> n;
vector<string> a(n + 5);
for (int i = 0; i < n; i++) {
cin >> a[i];
}
int m = a[0].size();
int res = 0;
Node* root = new Node();
for (int i = 0; i < n; i++) {
string s = a[i];
Node* cur = root;
int sum = 0; // 重复的后缀
for (int j = s.size() - 1; j >= 0; j--) {
res ++; // 所有后缀
int u = s[j] - 'a';
if (cur -> son[u] == nullptr) {
cur -> son[u] = new Node();
}
cur = cur -> son[u];
cur -> cnt++;
if (cur -> cnt >= 2) {
sum++;
}
}
res -= sum;
}
cout << res << endl;
}
F. Inversion Pairs
题意:给定一个字符串,只有 '0', '1', '?' ,其中 '?' 可以变成 '0' 或 '1',求逆序队的最大数量。
题解:对于所有的 '?' 一定存在一个分界点,使得前一部分填 '1',后一部分填 '0'。如果前一部分有一个位置为 0,将它放在所有的 1 后面,一定更优。
考虑先将所有的 '?' 视为 '0',然后从左往右依次变为 '1'。维护最大值即可。
void slove() {
int n; cin >> n;
string s; cin >> s;
s = "?" + s;
int pre1 = 0;
LL ans = 0, res = 0;
for (int i = 1; i <= n; i++) {
if (s[i] == '1') pre1++;
else {
res += pre1;
}
}
ans = res;
int aft0 = n - pre1;
pre1 = 0;
for (int i = 1; i <= n; i++) {
if (s[i] == '1') {
pre1++;
} else if (s[i] == '0') {
aft0--;
} else {
aft0--;
res -= pre1;
res += aft0;
pre1++;
ans = max(res, ans);
}
}
cout << ans << endl;
}
J. Sichuan Provincial Contest
题意:给定一棵树,书上的节点为对应位置的字符串的字符。计算所有简单路径恰好包含 "SCCPC" 的数量。
题解:树形DP,f(u, [i = 0~4]) 表示 u 的子树中,包含目标字符串的前缀 [0, i] 的方案数。g(u, [i = 0~4]) 表示 u 的子树中,包含目标字符串的后缀 [i, 4] 的方案数。
方案计算分为两部分:
- 当前这个节点的子树就存在目标字符串:f(u, 4) + g(u, 0)。
- 可以由两个链拼接而成目标字符串,中间节点进行拼接:f(v, i - 1) * (u 的子数组中,后缀为 [i + 1, 4] 的方案数之和)。后一部分可以对 u 的子树后缀方案数求和,然后减去该链即可。
const int N = 1e6 + 5;
vector<int> g[N];
string s;
int n;
LL res;
LL pre[N][5], aft[N][5];
string t = "SCCPC";
void dfs(int u, int fa) {
if (s[u] == t[0]) {
pre[u][0] = 1;
}
if (s[u] == t[4]) {
aft[u][4] = 1;
}
vector<LL> sum(5); // u 的子树后缀方案数之和
for (int v : g[u]) {
if (v == fa) continue;
dfs(v, u);
for (int i = 0; i <= 4; i++) {
sum[i] += aft[v][i];
if (s[u] == t[i]) {
if (i - 1 >= 0) {
pre[u][i] += pre[v][i - 1];
}
if (i + 1 <= 4) {
aft[u][i] += aft[v][i + 1];
}
}
}
}
res += pre[u][4] + aft[u][0];
for (int v : g[u]) {
if (v == fa) continue;
for (int i= 1; i <= 3; i++) {
if (s[u] == t[i]) {
res += pre[v][i - 1] * (sum[i + 1] - aft[v][i + 1]);
}
}
}
}
void slove() {
res = 0;
cin >> n;
cin >> s; s = "?" + s;
for (int i = 1; i <= n; i++) {
g[i].clear();
for (int j = 0; j <= 4; j++) {
pre[i][j] = aft[i][j] = 0;
}
}
for (int i = 1; i <= n - 1; i++) {
int u, v; cin >> u >> v;
g[u].emplace_back(v);
g[v].emplace_back(u);
}
dfs(1, -1);
cout << res << endl;
}
K. Point Divide and Conquer
题意:给定一颗树和对于顶点的排列,按照排列依次将树中的顶点删除,然后添加到新的树中,对于原树的若干个连通块,依然按照排列顺序将点删除,并且添加到新的树的节点下。求新树中每个节点的父节点编号。
题解:反向遍历排列,对于当前点 u,遍历所有邻居 v,如果 v 所在排列在 u 之后,并且不是一个连通块中,就将 v 所在连通块根的父亲设为 u,并且合并连通块,将 v 所在连通块挂在 u 下。
const int N = 1e5 + 5;
int a[N], p[N], pos[N];
vector<int> g[N];
int n;
int find(int x) {
if (p[x] != x) p[x] = find(p[x]);
return p[x];
}
void slove() {
cin >> n;
for (int i = 1; i <= n; i++) {
g[i].clear();
p[i] = i;
}
for (int i = 1; i <= n; i++) {
cin >> a[i];
pos[a[i]] = i;
}
for (int i = 1; i <= n - 1; i++) {
int u, v; cin >> u >> v;
g[u].emplace_back(v);
g[v].emplace_back(u);
}
vector<int> res(n + 5);
for (int i = n; i >= 1; i--) {
int u = a[i];
for (int v : g[u]) {
int pa = find(u), pb = find(v);
if (pos[v] > i && pa != pb) {
res[find(v)] = u;
p[pb] = u;
}
}
}
for (int i = 1; i <= n; i++) {
cout << res[i] << " ";
}
cout << endl;
}
浙公网安备 33010602011771号