G.Longest Path
拓扑排序
| #include <bits/stdc++.h> |
| using namespace std; |
| using ll = long long; |
| int dp[100010], d[100010]; |
| void solve() { |
| int n, m; scanf("%d%d", &n, &m); |
| vector<int> g[n + 1]; |
| for (int i = 1;i <= m;i++) { |
| int a, b; |
| scanf("%d%d", &a, &b); |
| g[a].push_back(b); |
| d[b] ++; |
| } |
| queue<int> q; |
| for (int i = 1;i <= n;i++) if (!d[i]) q.push(i); |
| while (!q.empty()) { |
| int x = q.front(); q.pop(); |
| for (auto y : g[x]) { |
| if (dp[x] + 1 > dp[y]) { |
| |
| dp[y] = dp[x] + 1; |
| } |
| d[y] --; |
| if (!d[y]) q.push(y); |
| } |
| } |
| printf("%d\n", *max_element(dp + 1, dp + n + 1)); |
| } |
| |
| int main() { |
| solve(); |
| return 0; |
| } |
I.Coins
表示,当前枚举到第个硬笔,有个硬币正面向上的概率。
| #include <bits/stdc++.h> |
| using namespace std; |
| using ll = long long; |
| constexpr int mod = 1e9 + 7; |
| long double dp[3010][3010]; |
| |
| void solve() { |
| int n; cin >> n; |
| vector<long double> p(n + 1); |
| for (int i = 1;i <= n;i++) cin >> p[i]; |
| dp[1][0] = 1.0 - p[1]; |
| dp[1][1] = p[1]; |
| for (int i = 2;i <= n;i++) { |
| for (int j = 0;j <= i;j++) { |
| dp[i][j] = dp[i - 1][j] * (1.0 - p[i]); |
| if (j > 0) dp[i][j] += dp[i - 1][j - 1] * p[i]; |
| } |
| } |
| long double ans = 0; |
| for (int i = n / 2 + 1;i <= n;i++) ans += dp[n][i]; |
| cout << fixed << setprecision(10) << ans << endl; |
| } |
| |
| int main() { |
| ios::sync_with_stdio(false); |
| cin.tie(nullptr); |
| solve(); |
| return 0; |
| } |
K.Stones
博弈论中,如果一个状态能够转移到必败态,则该状态为必胜态。
预处理出所有的必败态,由必败态进行状态转移。
| #include <bits/stdc++.h> |
| |
| using namespace std; |
| using ll = long long; |
| |
| int dp[100010], vis[100010]; |
| int a[110]; |
| void solve() { |
| int n, k; cin >> n >> k; |
| set<int> s; |
| for (int i = 0;i < n;i++) { |
| int x; cin >> x; |
| s.insert(x); |
| dp[x] = 1; |
| vis[x] = 1; |
| a[i] = x; |
| } |
| for (int i = 0;i < *s.begin();i++) dp[i] = 0, vis[i] = 1; |
| for (int i = 0;i <= k;i++) { |
| if (vis[i]) continue; |
| vis[i] = 1; |
| for (auto v : s) { |
| if (i - v >= 0) { |
| dp[i] |= (dp[i - v] == 0 ? 1 : 0); |
| } |
| else break; |
| } |
| } |
| cout << (dp[k] == 1 ? "First\n" : "Second\n"); |
| } |
| signed main() { |
| ios::sync_with_stdio(false); |
| cin.tie(nullptr); |
| solve(); |
| } |
L.Deque
两个人都想要自己的得分最大化。
记为在这一段进行游戏的最终的大小。
那么我们可以类似搜索,用区间求解。
| #include <bits/stdc++.h> |
| #define pb push_back |
| #define endl '\n' |
| using namespace std; |
| using ll = long long; |
| |
| ll dp[3010][3010]; |
| void solve() { |
| int n; cin >> n; |
| vector<ll> a(n + 1); |
| memset(dp, -0x3f, sizeof dp); |
| for (int i = 1; i <= n;i++) { |
| cin >> a[i]; |
| dp[i][i] = a[i]; |
| } |
| for (int len = 2;len <= n;len ++) { |
| for (int l = 1;l <= n;l ++) { |
| int r = l + len - 1; |
| dp[l][r] = max(a[l] - dp[l + 1][r], a[r] - dp[l][r - 1]); |
| } |
| } |
| |
| cout << dp[1][n] << endl; |
| |
| } |
| signed main(void) { |
| cin.tie(nullptr), cout.tie(nullptr) -> ios::sync_with_stdio(false); |
| solve(); |
| return 0; |
| } |
M.Candies
记表示到第个人,分份糖果的方案数。
但是我们需要用前缀和优化转移方程。
| #include <bits/stdc++.h> |
| #define endl '\n' |
| |
| using namespace std; |
| using ll = long long; |
| constexpr int mod = 1e9 + 7; |
| |
| ll dp[110][100010], pre[110][100010]; |
| void solve() { |
| int n, k; cin >> n >> k; |
| vector<int> a(n + 1); |
| ll sum = 0; |
| for (int i = 1;i <= n;i++ ) { |
| cin >> a[i]; |
| sum += 1ll * a[i]; |
| } |
| if (sum < k && k != 0) { |
| cout << 0 << endl; |
| return; |
| } |
| |
| for (int i = 0;i <= k;i++) pre[0][i] = 1; |
| for (int i = 1;i <= n;i++) pre[i][0] = 1; |
| |
| for (int i = 1;i <= n;i++) { |
| for (int j = 0;j <= k;j++) { |
| int r = min(j, a[i]); |
| dp[i][j] = pre[i - 1][j]; |
| if (j - r - 1 >= 0) dp[i][j] = (dp[i][j] - pre[i - 1][j - r - 1] + mod) % mod; |
| } |
| |
| for (int j = 1;j <= k;j++) pre[i][j] = (dp[i][j] + pre[i][j - 1]) % mod; |
| } |
| cout << (dp[n][k] + mod) % mod << endl; |
| } |
| signed main(void) { |
| cin.tie(nullptr), cout.tie(nullptr) -> ios::sync_with_stdio(false); |
| solve(); |
| return 0; |
| } |
M.Matching
状态压缩
| #include <bits/stdc++.h> |
| |
| using namespace std; |
| using ll = long long; |
| constexpr int mod = 1e9 + 7; |
| |
| int dp[23][1 << 23]; |
| void solve() { |
| int n; cin >> n; |
| vector<int> have(n + 1); |
| for (int i = 1;i <= n;i++) { |
| for (int j = 0;j < n;j++) { |
| int x; cin >> x; |
| if (x == 1) have[i] |= (1 << j); |
| } |
| } |
| dp[0][0] = 1; |
| for (int i = 1;i <= n;i++) { |
| for (int j = 0;j < (1 << n);j++) { |
| if (__builtin_popcount(j) == i - 1) { |
| for (int k = 0;k < n;k++) { |
| if ((have[i] >> k & 1) and (j >> k & 1) == 0) { |
| dp[i][j | (1 << k)] = (dp[i][j | (1 << k)] + dp[i - 1][j]) % mod; |
| } |
| } |
| } |
| } |
| } |
| |
| cout << dp[n][(1 << n) - 1] << '\n'; |
| } |
| |
| signed main(void) { |
| cin.tie(nullptr), cout.tie(nullptr)->ios::sync_with_stdio(false); |
| solve(); |
| return 0; |
| } |
P.Independent Set
类似没有上司的舞会,树形。
| #include <bits/stdc++.h> |
| |
| using namespace std; |
| using ll = long long; |
| constexpr int mod = 1e9 + 7; |
| |
| ll dp[100010][2]; |
| void solve() { |
| int n; cin >> n; |
| vector<vector<int>> g(n + 1); |
| for (int i = 0; i < n - 1;i++) { |
| int u, v; cin >> u >> v; |
| g[u].push_back(v); |
| g[v].push_back(u); |
| } |
| |
| auto dfs = [&](auto self, auto &g, auto x, auto fa)->void { |
| dp[x][0] = dp[x][1] = 1; |
| for (auto y : g[x]) { |
| if (y == fa) continue; |
| self(self, g, y, x); |
| dp[x][0] = dp[x][0] * (dp[y][0] + dp[y][1]) % mod; |
| dp[x][1] = dp[x][1] * dp[y][0] % mod; |
| } |
| return; |
| }; |
| dfs(dfs, g, 1, -1); |
| cout << (dp[1][0] + dp[1][1]) % mod << endl; |
| } |
| |
| signed main(void) { |
| cin.tie(nullptr), cout.tie(nullptr)->ios::sync_with_stdio(false); |
| solve(); |
| return 0; |
| } |
Q.Flowers
树状数组优化状态转移。
由于我们的值大小只会增大,所以可以用树状数组维护前缀最大值。
| #include <bits/stdc++.h> |
| |
| using namespace std; |
| using ll = long long; |
| constexpr int mod = 1e9 + 7; |
| constexpr int N = 200010; |
| int n; |
| ll dp[200010], c[N]; |
| void add(int x, ll d) { |
| while ( x <= n) { |
| c[x] = max(c[x], d); |
| x += x & -x; |
| } |
| } |
| ll query(int x) { |
| ll res = 0; |
| while (x > 0) { |
| res = max(res, c[x]); |
| x -= x & -x; |
| } |
| return res; |
| } |
| void solve() { |
| cin >> n; |
| vector<int> a(n + 1), h(n + 1); |
| for (int i = 1;i <= n;i++) cin >> h[i]; |
| for (int i = 1;i <= n;i++) cin >> a[i]; |
| |
| for (int i = 1;i <= n;i++) { |
| ll res = query(h[i] - 1); |
| dp[i] = max(dp[i], res + a[i]); |
| add(h[i], dp[i]); |
| } |
| cout << *max_element(dp + 1, dp + n + 1) << endl; |
| |
| } |
| |
| signed main(void) { |
| cin.tie(nullptr), cout.tie(nullptr)->ios::sync_with_stdio(false); |
| solve(); |
| return 0; |
| } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!