比赛链接:https://ac.nowcoder.com/acm/contest/7412
A - 牛牛和牛可乐的赌约
题解
计算模意义下的 $1 - frac{1}{n^m}$ 即可。
代码
#include <bits/stdc++.h> using namespace std; const int MOD = 1e9 + 7; int binpow(int a, int b) { int res = 1; while (b > 0) { if (b & 1) res = 1LL * res * a % MOD; a = 1LL * a * a % MOD; b >>= 1; } return res; } int inv(int n) { return binpow(n, MOD - 2); } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int t; cin >> t; while (t--) { int n, m; cin >> n >> m; cout << (1 - inv(binpow(n, m)) + MOD) % MOD << " "; } return 0; }
B - 牛牛和牛可乐的赌约2
题解
- $(0,0)$ 为必败态
- 可以移动到 $(0,0)$ 的 $(0,1),(0,2),(1,0),(2,0)$ 为必胜态
- 不得不移动到 $(0,1),(0,2),(1,0),(2,0)$ 的 $(3,0),(1,1),(0,3)$ 为必败态
- …………
以此类推,最终推得规律为 $x \% 3 = y \% 3$ 必败。
代码
#include <bits/stdc++.h> using namespace std; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int t; cin >> t; while (t--) { int x, y; cin >> x >> y; cout << ((x - y) % 3 == 0 ? "awsl" : "yyds") << " "; } return 0; }
C - 单词记忆方法
题解
递归求解每个配对括号内的和,再乘以括号外的倍数即可。
Tips
有可能括号外没有数字,所以 $dfs$ 中的 $mul$ 的初值根据判断条件有两种形式。
代码
#include <bits/stdc++.h> using namespace std; constexpr int N = 1e5 + 100; string s; int match[N]; void Match() { stack<int> stk; for (int i = 0; i < s.size(); i++) { if (s[i] == '(') { stk.push(i); } else if (s[i] == ')') { int last = stk.top(); stk.pop(); match[i] = last; match[last] = i; } } } long long dfs(int l, int r) { if (l > r) return 0; long long res = 0; while (l <= r) { long long val = 0; while (l <= r and isupper(s[l])) { val += s[l] - 'A' + 1; ++l; } if (s[l] == '(') { val = dfs(l + 1, match[l] - 1); l = match[l] + 1; } long long mul = 1; if (l <= r and isdigit(s[l])) { mul = 0; while (l <= r and isdigit(s[l])) { mul = mul * 10 + s[l] - '0'; ++l; } } res += val * mul; } return res; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); cin >> s; Match(); cout << dfs(0, s.size() - 1) << " "; return 0; }
D - 位运算之谜
题解
egin{equation} a + b = x end{equation}
egin{equation} a & b = y end{equation}
egin{equation} a + b = a oplus b + ((a & b) << 1) end{equation}
将 (1)(2) 代入 (3) 得:
egin{equation} x = a oplus b + (y << 1) onumber end{equation}
移项得:
egin{equation} a oplus b = x - (y << 1) onumber end{equation}
如果存在整数 $a,b$ 满足条件,那么得到的 $a oplus b$ 一定满足:
egin{equation} a oplus b ge 0 onumber end{equation}
egin{equation} (a oplus b) & (a & b) = 0 onumber end{equation}
代码
#include <bits/stdc++.h> using namespace std; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int t; cin >> t; while (t--) { long long x, y; cin >> x >> y; long long c = x - (y << 1); cout << (c >= 0 and ((c & y) == 0) ? c : -1) << " "; } return 0; }
G - 牛牛和字符串的日常
题解
KMP模板题,稍微改一下求最长前缀即可。(感觉以前哪场比赛好像考过这个)
代码
#include <bits/stdc++.h> using namespace std; const int N = 1e6 + 100; int Next[N]; string s, p; void init_Next() { Next[0] =Next[1] = 0; for (int i = 1; i < p.size(); i++) { int j = Next[i]; while (j and p[i] != p[j]) j = Next[j]; Next[i + 1] = (p[i] == p[j] ? j + 1 : 0); } } int KMP() { int mx = 0; int j = 0; for (int i = 0; i < s.size(); i++) { while (j and s[i] != p[j]) j = Next[j]; if (s[i] == p[j]) j++; mx = max(mx, j); } return mx; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); long long ans = 0; cin >> p; init_Next(); int t; cin >> t; while (t--) { cin >> s; ans += KMP(); } cout << ans << " "; return 0; }
H - 上学要迟到了
题解
单源最短路模板题。
代码
#include <bits/stdc++.h> using namespace std; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int n, m, s, t, T; cin >> n >> m >> s >> t >> T; vector<int> tim(m + 1), a(n + 1); for (int i = 1; i <= m; i++) cin >> tim[i]; for (int i = 1; i <= n; i++) cin >> a[i]; vector<vector<pair<int, int>>> G(n + 1); for (int u = 1; u + 1 <= n; u++) { int v = u + 1; G[u].emplace_back(v, T); G[v].emplace_back(u, T); } vector<int> last(m + 1); for (int i = 1; i <= n; i++) { if (last[a[i]]) { int u = last[a[i]]; int v = i; G[u].emplace_back(v, tim[a[i]]); } last[a[i]] = i; } function<int(int, int)> Get_distance = [&](int s, int t) { vector<int> dis(n + 1, 1e9); vector<bool> vis(n + 1); priority_queue<pair<int, int>> pque; dis[s] = 0; pque.emplace(0, s); while (!pque.empty()) { int u = pque.top().second; pque.pop(); if (vis[u]) continue; vis[u] = true; for (auto i : G[u]) { int v = i.first, w = i.second; if (!vis[v] and dis[v] > dis[u] + w) { dis[v] = dis[u] + w; pque.emplace(-dis[v], i.first); } } } return dis[t]; }; cout << Get_distance(s, t) << " "; return 0; }
I - 迷宫
题解
计算从 $(1,1)$ 到 $(n,m)$ 的路径数目的状态转移方程为:
egin{equation} dp_{ij} = dp_{(i-1)j} + dp_{i(j-1)} onumber end{equation}
那么计算模数再加一维状压dp即可。
代码
#include <bits/stdc++.h> using namespace std; constexpr int MOD = 1e4 + 7; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int n, m; cin >> n >> m; vector<vector<int>> a(n + 1, vector<int>(m + 1)); for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) { cin >> a[i][j]; a[i][j] %= MOD; } vector<vector<bitset<MOD>>> dp(n + 1, vector<bitset<MOD>>(m + 1)); dp[1][1].set(a[1][1]); for (int i = 1; i <= n; i++) { for (int j = 1; j <= m; j++) { if (i == 1 and j == 1) continue; dp[i][j] |= (dp[i - 1][j] << a[i][j]) | (dp[i - 1][j] >> (MOD - a[i][j])); dp[i][j] |= (dp[i][j - 1] << a[i][j]) | (dp[i][j - 1] >> (MOD - a[i][j])); } } cout << dp[n][m].count() << " "; return 0; }
J - 树上行走
题解
Tips
一个结点的父亲不一定是 $fa[i]$,应该用 $Find(i)$ 。
代码
#include <bits/stdc++.h> using namespace std; constexpr int N = 2e5 + 100; int fa[N], son_num[N]; int Find(int x) { return fa[x] == x ? fa[x] : fa[x] = Find(fa[x]); } void Union(int x, int y) { x = Find(x); y = Find(y); if (x != y) { fa[y] = x; son_num[x] += son_num[y]; } } void Init() { for (int i = 0; i < N; i++) { fa[i] = i; son_num[i] = 1; } } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); Init(); int n; cin >> n; vector<int> a(n); for (int i = 0; i < n; i++) cin >> a[i]; for (int i = 0; i < n - 1; i++) { int x, y; cin >> x >> y; --x, --y; if (a[x] == a[y]) Union(x, y); } int mx = *max_element(son_num, son_num + n); cout << count(son_num, son_num + n, mx) * mx << " "; for (int i = 0; i < n; i++) { if (son_num[Find(i)] == mx) { cout << i + 1 << ' '; } } return 0; }