2146 字
11 分钟
abc456
NOTE
A - Dice
关键词:签到
思路
显然三个骰子可以扔出的点数满足 。
Code
// Problem: AT ABC456 A// Contest: AtCoder - AtCoder Beginner Contest 456// URL: https://atcoder.jp/contests/abc456/tasks/abc456_a// Time: 2026-05-03 12:12:03#include <bits/stdc++.h>using namespace std;
#define endl '\n'
typedef long long ll;typedef unsigned long long ull;typedef pair<int, int> pii;typedef pair<double, double> pdd;typedef pair<long long, long long> pll;
const int dx[] = {-1, 0, 1, 0, -1, 1, 1, -1};const int dy[] = {0, 1, 0, -1, 1, 1, -1, -1};const int inf = 0x3f3f3f3f;const int N = 0;
int main(){ int x; cin >> x;
if (x >= 3 && x <= 18) cout << "Yes" << endl; else cout << "No" << endl;
return 0;}B - 456
关键词:暴力,签到
思路
总共有 216 种情况,暴力枚举判断即可。
Code
// Problem: AT ABC456 B// Contest: AtCoder - AtCoder Beginner Contest 456// URL: https://atcoder.jp/contests/abc456/tasks/abc456_b// Time: 2026-05-03 12:12:04#include <bits/stdc++.h>using namespace std;
#define endl '\n'
typedef long long ll;typedef unsigned long long ull;typedef pair<int, int> pii;typedef pair<double, double> pdd;typedef pair<long long, long long> pll;
const int dx[] = {-1, 0, 1, 0, -1, 1, 1, -1};const int dy[] = {0, 1, 0, -1, 1, 1, -1, -1};const int inf = 0x3f3f3f3f;const int N = 6;
int a[3][N];
int main(){ for (int i = 0; i < 3; i++) for (int j = 0; j < 6; j++) cin >> a[i][j];
int res = 0; for (int i = 0; i < 6; i++) for (int j = 0; j < 6; j++) for (int k = 0; k < 6; k++) { if ((a[0][i] == 4 && a[1][j] == 5 && a[2][k] == 6) || (a[0][i] == 4 && a[1][j] == 6 && a[2][k] == 5) || (a[0][i] == 5 && a[1][j] == 4 && a[2][k] == 6) || (a[0][i] == 5 && a[1][j] == 6 && a[2][k] == 4) || (a[0][i] == 6 && a[1][j] == 4 && a[2][k] == 5) || (a[0][i] == 6 && a[1][j] == 5 && a[2][k] == 4)) res++; } cout << fixed << setprecision(10) << 1.0 * res / 216 << endl; return 0;}C - Not Adjacent
关键词:思维、模拟
思路
如果存在 的位置,这两个字符不能同时选取,因此答案可以通过在第 个与第 个字符之间分割,计算每个块的数量并求和得到。
If S = abbcabcbaaabc ab|bcabcba|a|abc 3 + 28 + 1 + 6 = 38Code
// Problem: AT ABC456 C// Contest: AtCoder - AtCoder Beginner Contest 456// URL: https://atcoder.jp/contests/abc456/tasks/abc456_c// Time: 2026-05-03 12:12:05#include <bits/stdc++.h>using namespace std;
#define endl '\n'
typedef long long ll;typedef unsigned long long ull;typedef pair<int, int> pii;typedef pair<double, double> pdd;typedef pair<long long, long long> pll;
const int dx[] = {-1, 0, 1, 0, -1, 1, 1, -1};const int dy[] = {0, 1, 0, -1, 1, 1, -1, -1};const int inf = 0x3f3f3f3f;const int N = 0;const int mod = 998244353;
int main(){ string s; cin >> s;
int n = (int) s.size();
ll res = 0, idx = 0;
for (int i = 0; i < n; i++) { if (s[i] == s[i + 1] || i + 1 == n) { res += (ll) (i - idx + 1) * (i - idx + 2) / 2; idx = i + 1; } }
cout << res % mod << endl; return 0;}D - Not Adjacent 2
关键词:DP,统计子序列
思路
在构建子序列时,当我们想要把当前字符(比如 a)加入到某个现有的子序列末尾时,我们只关心这个现有的子序列,最后一个字符是什么。这就提示我们,必须把 DP 的状态按照“以什么字符结尾”来进行分类。
因为字符集只有 a, b, c 三个字符,我们可以只维护三个变量:
- :表示目前为止,以字符
a结尾的合法子序列数量。 - :表示目前为止,以字符
b结尾的合法子序列数量。 - :表示目前为止,以字符
c结尾的合法子序列数量。
假设我们现在从左到右遍历字符串,当前遇到了一个字符 a,我们该如何更新这三个变量呢?
对于以 a 结尾的子序列,它的来源有四部分:
- 旧的序列:之前已经构成的以
a结尾的子序列。因为我们是“子序列”提取,我们可以选择不把当前这个a纳入进来,所以原来的 个子序列依然存在且合法。 - 自立门户:当前这个字符
a自己单独组成一个长度为 1 的子序列"a"。这贡献了 个。 - 接在
b后面:把当前字符a接在所有合法的、以b结尾的子序列后面,构成了新的以a结尾的子序列。这贡献了 个。 - 接在
c后面:把当前字符a接在所有合法的、以c结尾的子序列后面。这贡献了 个。
把它们加起来,遇到字符 a 时,新的 的状态转移方程就是:
而此时,因为当前字符是 a,它并没有产生新的以 b 或 c 结尾的子序列,所以有:
,
同理,如果遇到了字符 b 或 c,只需要把上面的公式替换一下字母即可。
Code
// Problem: AT ABC456 D// Contest: AtCoder - AtCoder Beginner Contest 456// URL: https://atcoder.jp/contests/abc456/tasks/abc456_d// Time: 2026-05-03 12:12:06#include <bits/stdc++.h>using namespace std;
#define endl '\n'
typedef long long ll;typedef unsigned long long ull;typedef pair<int, int> pii;typedef pair<double, double> pdd;typedef pair<long long, long long> pll;
const int dx[] = {-1, 0, 1, 0, -1, 1, 1, -1};const int dy[] = {0, 1, 0, -1, 1, 1, -1, -1};const int inf = 0x3f3f3f3f;const int N = 0;const int mod = 998244353;
ll res;
int main(){ string s; cin >> s;
ll dp[3] = {0, 0, 0};
for (char c: s) { if (c == 'a') dp[0] = (dp[0] + dp[1] + dp[2] + 1) % mod; else if (c == 'b') dp[1] = (dp[0] + dp[1] + dp[2] + 1) % mod; else dp[2] = (dp[0] + dp[1] + dp[2] + 1) % mod; }
ll res = (dp[0] + dp[1] + dp[2]) % mod; cout << res << endl;
return 0;}E - Endless Holidays
关键词:思维,图论,判断环
思路
TIP由于可以选择留在当前的城市,所以在建图时需要把每个点自身加进图里(自环)。
既然 Takahashi 每天都在移动或停留,我们可以用一个二元组 (u, d) 来表示他当前的状态:u 表示当前所在的城市,d 表示当前是星期几(为便于取模从 0 开始)。考虑这个状态图中的有效状态与转移过程:
- 有效状态:只有当
S[u][d] == 'o'时,这个状态才是合法的(因为必须是节假日)。 - 状态转移:如果高桥今天在
(u, d),明天他可以去任何一个相邻的城市v(或者留在u)。那么就会有一条从(u, d)指向(v, (d + 1) % W)的有向边。当然,前提是目标状态也必须是合法的。
假如他想要永远移动下去,就意味着必须要找一条无限长的路径,也就是图中存在环。
NOTE怎么判断图里有没有环?我们可以用一种“反向拓扑排序”思想:不断剪除死胡同。
- 我们统计每个合法状态的出度,即它能走到多少个合法的明天状态。
- 如果某个状态的出度为 0,说明它是个死胡同,走到这里就结束了,我们把它从图里删掉。
- 删除它之后,可能会导致指向它的那些状态也变成死胡同(出度减 1)。如果它们出度也变成了 0,就继续删。
- 如果我们能把图里所有的有效状态都删光,说明处处都是死胡同,输出
No。- 如果最后还有状态没被删掉,说明它们形成了环,输出
Yes。
Code
// Problem: AT ABC456 E// Contest: AtCoder - AtCoder Beginner Contest 456// URL: https://atcoder.jp/contests/abc456/tasks/abc456_e// Time: 2026-05-03 12:12:07#include <bits/stdc++.h>using namespace std;
#define endl '\n'
typedef long long ll;typedef unsigned long long ull;typedef pair<int, int> pii;typedef pair<double, double> pdd;typedef pair<long long, long long> pll;
const int dx[] = {-1, 0, 1, 0, -1, 1, 1, -1};const int dy[] = {0, 1, 0, -1, 1, 1, -1, -1};const int inf = 0x3f3f3f3f;const int N = 1e5 + 10;
void solve(){ int n, m, w; cin >> n >> m;
vector<vector<int>> adj(n + 1);
for (int i = 0; i < m; i++) { int u, v; cin >> u >> v; adj[u].push_back(v), adj[v].push_back(u); }
for (int i = 1; i <= n; i++) adj[i].push_back(i);
cin >> w;
vector<string> s(n + 1); for (int i = 1; i <= n; i++) cin >> s[i];
// out[u][d] 表示状态 (u, d) 有多少个合法的下一个状态 vector<vector<int>> out(n + 1, vector<int>(w, 0)); int valid_states = 0;
for (int u = 1; u <= n; u++) for (int d = 0; d < w; d++) if (s[u][d] == 'o') { valid_states++; int nxt = (d + 1) % w; for (int v: adj[u]) { if (s[v][nxt] == 'o') out[u][d]++; } }
queue<pii> q; for (int u = 1; u <= n; u++) for (int d = 0; d < w; d++) if (s[u][d] == 'o' && out[u][d] == 0) q.push({u, d});
int removed = 0; while (!q.empty()) { auto [u, d] = q.front(); q.pop();
removed++;
int prev_d = (d - 1 + w) % w; for (int v: adj[u]) { if (s[v][prev_d] == 'o') { out[v][prev_d]--; if (out[v][prev_d] == 0) q.push({v, prev_d}); } } }
if (removed < valid_states) cout << "Yes" << endl; else cout << "No" << endl;}
int main(){ ios::sync_with_stdio(false); cin.tie(0);
int T; cin >> T;
while (T--) solve();
return 0;}