A. Happy New Year 2025
模拟
代码实现
a, b = map(int, input().split())
print((a+b)**2)
B. 9x9 Sum
模拟
代码实现
#include <bits/stdc++.h>
#define rep1(i, n) for (int i = 1; i <= (n); ++i)
using namespace std;
int main() {
int x;
cin >> x;
int ans = 0;
rep1(i, 9)rep1(j, 9) {
if (i*j != x) ans += i*j;
}
cout << ans << '\n';
return 0;
}
C. Snake Numbers
讨论小于 \(x\) 的数会比较方便,所以不妨设 \(f(x)\) 表示小于 \(x\) 的蛇数个数
那么答案就是 \(f(r+1)-f(l)\)
假设 \(x\) 有 \(n\) 位数
可以先统计不足 \(n\) 位数的蛇数个数
对于这种情况,只需考虑枚举每位数的开头的数字 \(h\),后面每一位上可以选的数字为 \(0 \sim h-1\),所以方案数为 \(h^{k-1}\)
再来考虑 \(n\) 位数的贡献
当开头的数字 \(h\) 小于 \(x\) 的开头数字时,后面 \(n-1\) 位都有 \(0 \sim h-1\) 个数可以选择,所以方案数为 \(h^{n-1}\)
最后再来考虑开头的数字填 \(x\) 的开头数字时,再分别考虑后面的每一位,假设当前枚举到第 \(i\) 位,如果 \(x\) 在这一位上的数字大于等于开头的数字,那么贡献就是 \(h^{n-i}\)(意思就是这一位到最低位上的数字都有 \(0 \sim h-1\) 种选择),并立即跳出循环;否则,在当前位上可以填 \(0 \sim x\) 在第 \(i\) 位上的数 \(-1\),后面所有位可以填 \(0 \sim h-1\)
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using ll = long long;
ll pw(ll x, int p) {
ll res = 1;
rep(i, p) res *= x;
return res;
}
ll f(ll r) {
r++;
vector<int> digits;
for (char c : to_string(r)) {
digits.push_back(c-'0');
}
int n = digits.size();
ll res = 0;
for (int k = 1; k < n; ++k) {
for (int h = 1; h <= 9; ++h) res += pw(h, k-1);
}
for (int h = 1; h < digits[0]; ++h) res += pw(h, n-1);
int h = digits[0];
for (int i = 1; i < n; ++i) {
if (digits[i] >= h) {
res += pw(h, n-i);
break;
}
res += pw(h, n-i-1) * digits[i];
}
return res;
}
int main() {
ll l, r;
cin >> l >> r;
ll ans = f(r) - f(l-1);
cout << ans << '\n';
return 0;
}
D. Snaky Walk
需要维护方向的bfs,但由于这里是二维网格所以不需要维护方向

考虑以上的网格图,所有黑格子的横纵坐标之和的积偶性是一样的,为偶数,对于白格子也是,为奇数
行走路径的方向为
--|--|--
或
|--|--|--
可以通过枚举奇偶性来确定这两种情况
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using P = pair<int, int>;
int main() {
int h, w;
cin >> h >> w;
vector<string> s(h);
rep(i, h) cin >> s[i];
const int INF = 1001001001;
int ans = INF;
rep(par, 2) {
vector dist(h, vector<int>(w, INF));
queue<P> q;
auto push = [&](int i, int j, int d) {
if (i < 0 or j < 0 or i >= h or j >= w) return;
if (s[i][j] == '#') return;
if (dist[i][j] != INF) return;
dist[i][j] = d;
q.emplace(i, j);
};
rep(i, h)rep(j, w) if (s[i][j] == 'S') push(i, j, 0);
while (q.size()) {
auto [i, j] = q.front(); q.pop();
int d = dist[i][j];
if (s[i][j] == 'G') ans = min(ans, d);
if ((i+j)%2 == par) {
push(i-1, j, d+1);
push(i+1, j, d+1);
}
else {
push(i, j-1, d+1);
push(i, j+1, d+1);
}
}
}
if (ans == INF) ans = -1;
cout << ans << '\n';
return 0;
}
E. Digit Sum Divisible 2
一道贴近ARC风格的题
当 \(n\) 不超过 \(6\) 位数时,直接暴力即可
对于一般情况,可以考虑构造 2024/2025 这样一边满足数位和是 \(8\) 且是8的倍数,另一边满足数位和是 \(9\) 且是 \(9\) 的倍数的数
考虑只取 \(n\) 的高位前三位+1,然后通过不断加 \(1\),把它变成数位和是 \(8\),接下来只需在后面添加若干个 0 即可
代码实现
#include <bits/stdc++.h>
using namespace std;
int keta(int a) {
int res = 0;
for (char c : to_string(a)) {
res += c-'0';
}
return res;
}
bool good(int a) {
return a%keta(a) == 0;
}
int main() {
string s;
cin >> s;
if (s.size() <= 6) {
int n = stoi(s);
for (int a = n; a < n*2; ++a) {
if (good(a) and good(a+1)) {
cout << a << '\n';
return 0;
}
}
puts("-1");
return 0;
}
int n = stoi(s.substr(0, 3))+1;
while (keta(n) != 8) n++;
cout << n << string(s.size()-3, '0') << '\n';
return 0;
}
F. Count Arrays
考虑对点 \(i\) 连一条有向边指向点 \(A_i\),这样就得到了一个基环树森林
对于一个基环树而言,环里的点的点权一定是相同的,那么我们可以将整个环缩点。
另外,这个基环树是个内向树
然后对缩点后的树跑树形dp
记 dp[v][i] 表示在以点 \(v\) 为根的子树中满足 \(x_v = i\) 的方案数
转移方程:
时间复杂度为 \(O(NM^2)\)
考虑对 \(\sum\limits_{j \leqslant i} dp[c][j]\) 这部分进行加速,可以利用前缀和
代码实现
#include <bits/stdc++.h>
#include <atcoder/all>
using namespace atcoder;
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using mint = modint998244353;
int main() {
int n, m;
cin >> n >> m;
vector<int> a(n);
rep(i, n) cin >> a[i], a[i]--;
scc_graph g(n);
rep(i, n) g.add_edge(i, a[i]);
auto groups = g.scc();
int s = groups.size();
vector<int> gid(n);
rep(i, s) for (int v : groups[i]) gid[v] = i;
vector<int> pa(s, s);
rep(i, n) {
int u = gid[i], v = gid[a[i]];
if (u == v) continue;
pa[u] = v;
}
vector dp(s+1, vector<mint>(m, 1));
rep(i, s) {
rep(j, m-1) dp[i][j+1] += dp[i][j];
rep(j, m) dp[pa[i]][j] *= dp[i][j];
}
mint ans = dp[s][m-1];
cout << ans.val() << '\n';
return 0;
}
浙公网安备 33010602011771号