T1: 子集和(四)
可以先求出由这 个数组成 的方案数,这是简单的完全背包问题
记 dp[t]
表示组成 的方案数
不选择 的前提下组成 的方案数也就是把 减掉至少包含一个 的方案
回想一下:
所以每个问题的答案就是
代码实现
#include <bits/stdc++.h> #define rep(i, n) for (int i = 0; i < (n); ++i) using std::cin; using std::cout; using std::vector; using std::istream; using std::ostream; using ll = long long; //const int mod = 998244353; const int mod = 1000000007; struct mint { ll x; mint(ll x=0):x((x%mod+mod)%mod) {} mint operator-() const { return mint(-x); } mint& operator+=(const mint a) { if ((x += a.x) >= mod) x -= mod; return *this; } mint& operator-=(const mint a) { if ((x += mod-a.x) >= mod) x -= mod; return *this; } mint& operator*=(const mint a) { (x *= a.x) %= mod; return *this; } mint operator+(const mint a) const { return mint(*this) += a; } mint operator-(const mint a) const { return mint(*this) -= a; } mint operator*(const mint a) const { return mint(*this) *= a; } mint pow(ll t) const { if (!t) return 1; mint a = pow(t>>1); a *= a; if (t&1) a *= *this; return a; } // for prime mod mint inv() const { return pow(mod-2); } mint& operator/=(const mint a) { return *this *= a.inv(); } mint operator/(const mint a) const { return mint(*this) /= a; } }; istream& operator>>(istream& is, mint& a) { return is >> a.x; } ostream& operator<<(ostream& os, const mint& a) { return os << a.x; } mint dp[10005]; int main() { int n, t; cin >> n >> t; vector<int> a(n); rep(i, n) cin >> a[i]; dp[0] = 1; rep(i, n) { for (int j = 0; j <= t-a[i]; ++j) { dp[j+a[i]] += dp[j]; } } // 考虑减掉至少包含一个 a[i] 的方案 rep(i, n) { if (t >= a[i]) { dp[t] -= dp[t-a[i]]; } cout << dp[t] << '\n'; if (t >= a[i]) { dp[t] += dp[t-a[i]]; } } return 0; }
T2:路径问题
可以考虑倍增法
记 jump[i][j]
表示从点 出发,走 条边后到达的点
转移式:
记 mx[i][j]
表示从点 出发,经过 条边的路径的边权最大值
转移式:
代码实现
#include <bits/stdc++.h> #define rep(i, n) for (int i = 1; i <= (n); ++i) using std::cin; using std::cout; using std::max; using std::vector; const int MX = 500005; int jump[MX][21]; int mx[MX][21]; inline void chmax(int& x, int y) { if (x < y) x = y; } int main() { int n, k; cin >> n >> k; rep(i, n) cin >> jump[i][0]; rep(i, n) cin >> mx[i][0]; rep(j, 20)rep(i, n) { jump[i][j] = jump[jump[i][j-1]][j-1]; mx[i][j] = max(mx[i][j-1], mx[jump[i][j-1]][j-1]); } rep(i, n) { int v = i, ans = 0; for (int j = 0; j <= 20; ++j) { if (k>>j&1) { chmax(ans, mx[v][j]); v = jump[v][j]; } } cout << ans << '\n'; } return 0; }
T3:航海探险
可以考虑用带权并查集来维护
记 dist[i]
表示点 到其祖先节点的距离
需要将每个点拆成两个点,也就是 方向和 方向
代码实现
#include <bits/stdc++.h> #define rep(i, n) for (int i = 1; i <= (n); ++i) using std::cin; using std::cout; using std::min; using std::vector; const int MX = 1e5+5; int fa[MX]; int dist[MX]; int find(int x) { if (fa[x] == x) return x; int fx = find(fa[x]); dist[x] += dist[fa[x]]; return fa[x] = fx; } inline void connect(int a, int b, int d) { int ra = find(a), rb = find(b); if (ra == rb) return; dist[ra] = d-dist[a]+dist[b]; fa[ra] = rb; } int main() { int n, m; cin >> n >> m; // i x 方向 // i+n y 方向 rep(i, n*2) fa[i] = i; while (m--) { char type; cin >> type; switch (type) { case 'E': { int a, b, e; cin >> a >> b >> e; connect(a, b, e); connect(a+n, b+n, 0); break; } case 'S': { int a, b, e; cin >> a >> b >> e; connect(a+n, b+n, e); connect(a, b, 0); break; } case 'W': { int a, b, e; cin >> a >> b >> e; connect(b, a, e); connect(a+n, b+n, 0); break; } case 'N': { int a, b, e; cin >> a >> b >> e; connect(b+n, a+n, e); connect(a, b, 0); break; } case '?': { int a, b; cin >> a >> b; if (find(a) == find(b) and find(a+n) == find(b+n)) { cout << abs(dist[a]-dist[b])+abs(dist[a+n]-dist[b+n]) << '\n'; } else puts("?"); break; } } } return 0; }
T4 : 没有考试的天数(二)
将 中 的倍数都去除便是答案
可以考虑容斥原理:
中是 的倍数的数有 个
中既是 的倍数又是 的倍数的数有 个
中是 中每个数的倍数的数有 个
代码实现
#pragma GCC optimize ("O2") #pragma GCC optimize ("unroll-loops") #pragma GCC target ("avx2" #include <bits/stdc++.h> #define rep(i, n) for (int i = 0; i < (n); ++i) using std::cin; using std::cout; using std::lcm; using std::vector; using ll = long long; int main() { cin.tie(nullptr) -> sync_with_stdio(false); int n; ll t; cin >> n >> t; vector<ll> a(n); rep(i, n) cin >> a[i]; ll ans = t; for (int i = 1; i < 1<<n; ++i) { ll l = 1; rep(j, n) if (i>>j&1) { if (lcm(l, a[j]) > t) { l = -1; break; } l = lcm(l, a[j]); } if (l != -1) { // 注意一定要特判,不然会超时 if (__builtin_parity(i)) ans -= t/l; else ans += t/l; } } cout << ans << '\n'; return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!