T1:Legendary Players
模拟
代码实现
table = ''' tourist 3858 ksun48 3679 Benq 3658 Um_nik 3648 apiad 3638 Stonefeang 3630 ecnerwala 3613 mnbvmar 3555 newbiedmy 3516 semiexp 3481 ''' s = input() for line in table.strip().split('\n'): user, rating = line.split() if user == s: print(rating)
T2:Measure
模拟
代码实现
#include <bits/stdc++.h> using namespace std; int main() { int n; cin >> n; string s(n+1, '-'); for (int j = 9; j >= 1; --j) { if (n%j != 0) continue; for (int i = 0; i <= n; i += n/j) { s[i] = '0'+j; } } cout << s << '\n'; return 0; }
T3:False Hope
简单题意:
现在有一个 的方格 ,每一个格子中有一个元素,但是刚开始你不知道所有方格中权值的情况。
现在你将要进行 次操作,每一次操作你将要选择一个没有被翻开的位置。
如果在一次操作中,在将要翻转的格子的横向或纵向或对角线上已经有两个已经翻开的格子并且满足同一方向上有两个格子上的数相同,那么你就会感到沮丧。
求:以任意顺序翻开所有格子,你不会感到沮丧的概率。
分析:
暴力枚举 种顺序即可
代码实现
#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() { vector<int> c(9); rep(i, 9) cin >> c[i]; vector<int> p(9); rep(i, 9) p[i] = i; int cnt = 0, tot = 0; do { bool ok = true; auto f = [&](int i, int j, int k) { vector<P> d; d.emplace_back(p[i], c[i]); d.emplace_back(p[j], c[j]); d.emplace_back(p[k], c[k]); sort(d.begin(), d.end()); if (d[0].second == d[1].second) ok = false; }; f(0, 1, 2); f(3, 4, 5); f(6, 7, 8); f(0, 3, 6); f(1, 4, 7); f(2, 5, 8); f(0, 4, 8); f(2, 4, 6); if (ok) cnt++; tot++; } while (next_permutation(p.begin(), p.end())); double ans = 1.*cnt/tot; printf("%.10f\n", ans); return 0; }
T4:Minimum Width
二分
代码实现
#include <bits/stdc++.h> #define rep(i, n) for (int i = 0; i < (n); ++i) using namespace std; using ll = long long; int main() { int n, m; cin >> n >> m; vector<int> l(n); rep(i, n) cin >> l[i]; ll wa = 0, ac = 1e15; while (abs(ac-wa) > 1) { ll wj = (ac+wa)/2; auto f = [&](ll w) { int line = 0; ll rem = 0; rep(i, n) { if (rem >= l[i]+1) { rem -= l[i]+1; } else { line++; rem = w-l[i]; if (rem < 0) return false; } } return line <= m; }; if (f(wj)) ac = wj; else wa = wj; } cout << ac << '\n'; return 0; }
T5:Bus Stops
注意到 ,根据抽屉原理,一定会存在很多重复。考虑周期性,注意到,时间每经过 ,公交车的到达时间都是相同的,因此移动所需的时间也是相同的。 所以只需 模拟出发时间为 的答案,就能做到 询问了。
代码实现
#include <bits/stdc++.h> #define rep(i, n) for (int i = 0; i < (n); ++i) using namespace std; using ll = long long; int main() { int n, x, y; cin >> n >> x >> y; n--; vector<int> p(n), t(n); rep(i, n) cin >> p[i] >> t[i]; int m = 840; vector<ll> d(m); rep(si, m) { ll now = si+x; rep(i, n) { while (now%p[i]) now++; now += t[i]; } now += y; d[si] = now-si; } int q; cin >> q; rep(qi, q) { ll now; cin >> now; now += d[now%m]; cout << now << '\n'; } return 0; }
T6:Fighter Takahashi
注意到,如果当前能够选择打倒敌人和嗑药,显然选择优先打倒敌人一定不亏。因为先加后乘得到的战斗力一定大于先乘后加得到的战斗力。另外,在有多个敌人可以打倒的时候,无论选择优先打倒哪个敌人,高桥最后的战斗力都是一样的。
因此,能打倒的敌人立刻打倒是最优策略。如果没有药物,可以用优先队列来维护当前可以到达的敌人所在的点以及它的战斗力贪心地解决。
现在考虑有药的情况,假设有 个药
根据嗑药顺序,打倒敌人的时机也会发生变化,如果固定嗑药顺序的话,最佳战略就是前面提到的贪心。也就是说,固定嗑药顺序 的策略为
- 不嗑药能打倒多少敌人就打倒多少
- 药 能拿就拿
- 不嗑药能打倒多少敌人就打倒多少
- 药 能拿就拿
那么,本题通过枚举这 种拿药顺序就能解决!但这种做法的时间复杂度为 ,容易超时。
如果想降低枚举所有排列的时间复杂度,就需要用到状压dp。
当使用固定的药物集合时,打倒哪个敌人仅由高桥的战斗力决定,高桥的战斗力越高的话,能打倒的敌人的集合单调增大。
记 dp[S]
表示能使用的药的集合为 时高桥能达到的最大战斗力
时间复杂度就降到了
代码实现
#include <bits/stdc++.h> #define rep(i, n) for (int i = 0; i < (n); ++i) using namespace std; using ll = long long; using P = pair<int, int>; int main() { int n; cin >> n; vector<vector<int>> to(n); vector<int> es(n), eg(n); vector<int> mul(n), id(n); int m = 0; vector<int> dvs; es[0] = 0; eg[0] = 1; for (int i = 1; i < n; ++i) { int p, t, s, g; cin >> p >> t >> s >> g; --p; to[p].push_back(i); if (t == 1){ es[i] = s; eg[i] = g; } else { es[i] = -1; mul[i] = g; dvs.push_back(i); id[i] = m++; } } int m2 = 1<<m; const ll INF = 1001001001; vector<ll> dp(m2, -1); using PQ = priority_queue<P, vector<P>, greater<P>>; vector<PQ> mem_q(m2); vector<int> mem_nb(m2); auto push = [&](int s, ll p, PQ q, int nb) { while (q.size() and q.top().first <= p) { int v = q.top().second; q.pop(); if (es[v] != -1) p += eg[v]; for (int u : to[v]) { if (es[u] == -1) nb |= 1<<id[u]; else q.emplace(es[u], u); } } if (dp[s] < p) { dp[s] = min(p, INF); mem_q[s] = q; mem_nb[s] = nb; } }; { PQ q; q.emplace(0, 0); push(0, 0, q, 0); } rep(s, m2) { int nb = mem_nb[s]; rep(i, m) if (nb>>i&1) { int v = dvs[i]; ll p = dp[s]; PQ q = mem_q[s]; q.emplace(0, v); p *= mul[v]; p = min(p, INF); push(s|1<<i, p, q, nb^1<<i); } } if (dp[m2-1] != -1 and mem_q[m2-1].empty()) puts("Yes"); else puts("No"); return 0; }
T7:Counting Shortest Paths
补图上的的最短路计数
用 std::set
维护未访问过的点并进行
对于当前点 ,遍历集合 中的所有点,跳过和 有连边的点,更新其他点到点 的距离,并将点 从集合 中删除
关于最短路计数,这里可以开一个数组用来维护分层图上每一层上的点集,然后在分层图上做一遍 即可
代码实现
#include <bits/stdc++.h> #if __has_include(<atcoder/all>) #include <atcoder/all> using namespace atcoder; #endif #define rep(i, n) for (int i = 0; i < (n); ++i) using namespace std; using mint = modint998244353; using US = unordered_set<int>; int main() { int n, m; cin >> n >> m; vector<US> to(n); rep(i, m) { int a, b; cin >> a >> b; --a; --b; to[a].insert(b); to[b].insert(a); } const int INF = 1001001001; vector<int> dist(n, INF); queue<int> q; dist[0] = 0; q.push(0); US s; for (int i = 1; i < n; ++i) s.insert(i); while (q.size()) { int v = q.front(); q.pop(); vector<int> del; for (int u : s) { if (to[v].count(u)) continue; dist[u] = dist[v]+1; del.push_back(u); q.push(u); } for (int u : del) s.erase(u); } if (dist[n-1] == INF) { puts("-1"); return 0; } vector<mint> dp(n); dp[0] = 1; vector<vector<int>> vs(n); rep(i, n) if (dist[i] != INF) vs[dist[i]].push_back(i); rep(i, n-1) { mint tot; for (int v : vs[i]) tot += dp[v]; for (int v : vs[i+1]) { dp[v] = tot; for (int u : to[v]) { if (dist[u] == i) dp[v] -= dp[u]; } } } cout << dp[n-1].val() << '\n'; return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现