20230420 训练记录:dp
Digit Sum#
中有多少数是 的倍数。
。
数位 dp,
展开代码
#include <bits/stdc++.h>
using ll = long long;
int main() {
std::cin.tie(nullptr)->sync_with_stdio(false);
std::string s;
int d;
std::cin >> s >> d;
int n = s.size();
std::vector k(n, 0);
for (int i = 0; i < n; i++) {
k[i] = s[n - i - 1] - '0';
}
const int mod = 1000000007;
std::vector f(n + 1, std::vector(d, std::array<int, 2>{}));
f[0][0][0] = 1;
for (int i = 0; i < n; i++) {
for (int s = 0; s < d; s++) {
for (int _f : {0, 1}) {
for (int _d = 0; _d < 10; _d++) {
int new_s = (s + _d) % d;
int new_f = _d > k[i] || (_d == k[i] && _f == 1);
f[i + 1][new_s][new_f] = ((ll) f[i + 1][new_s][new_f] + f[i][s][_f]) % mod;
}
}
}
}
std::cout << (f[n][0][0] - 1 + mod) % mod << '\n';
return 0;
}
Permutation#
Grouping#
将物品分组,如果
在一组将会得到 的分。问所有分组情况下最大得分。
。
分成若干组包含一个子问题:分成两组。
状压,
💡 如何枚举非空子集
for (int j = i; j; --j &= i) { }
当然,本题需要非空、真子集,因此初始
int j = i & (i - 1)
(抹去最后一个)。
复杂度为
依二项式定理,
[1] sh %%%
展开代码
#include <bits/stdc++.h>
using ll = long long;
int main() {
std::cin.tie(nullptr)->sync_with_stdio(false);
int n;
std::cin >> n;
std::vector g(n, std::vector(n, 0));
for (auto &i : g) for (auto &j : i) std::cin >> j;
std::vector f(1 << n, -1LL);
f[0] = 0;
std::cout << [&, dp{[&](auto &&self, int i) -> ll {
if (~f[i]) return f[i];
f[i] = 0;
for (int j = 0; j < n; j++) if (i >> j & 1) {
for (int k = j + 1; k < n; k++) if (i >> k & 1) {
f[i] += g[j][k];
}
}
for (int j = i & (i - 1); j; --j &= i) {
f[i] = std::max(f[i], self(self, j) + self(self, i ^ j));
}
return f[i];
}}]{
return dp(dp, (1 << n) - 1);
}();
return 0;
}
Subtree#
将树的节点染成黑白,问
在树上唯一黑色连通块的方案数。
,不保证模数为素数。
容易处理出以
实际上
展开代码
可惜没有
#include <bits/stdc++.h>
using ll = long long;
int main() {
std::cin.tie(nullptr)->sync_with_stdio(false);
int n, m;
std::cin >> n >> m;
if (n == 1) {
std::cout << 1 % m << '\n';
std::exit(0);
}
std::vector g(n, std::vector(0, 0));
for (int i = 1; i < n; i++) {
int u, v;
std::cin >> u >> v;
u -= 1, v -= 1;
g[u].push_back(v);
g[v].push_back(u);
}
std::vector f(n, 1);
std::vector prefix{g}, suffix{g};
[&, dfs{[&](auto &&self, int u, int p) -> void {
for (int v : g[u]) if (v != p) {
self(self, v, u);
f[u] = (ll) f[u] * (1 + f[v]) % m;
}
std::fill(prefix[u].begin(), prefix[u].end(), 1);
for (int i = 1; i < (int) g[u].size(); i++) {
prefix[u][i] = prefix[u][i - 1];
if (int v = g[u][i - 1]; v != p) {
prefix[u][i] = (ll) prefix[u][i] * (f[v] + 1) % m;
}
}
std::fill(suffix[u].begin(), suffix[u].end(), 1);
for (int i = (int) g[u].size() - 2; ~i; i--) {
suffix[u][i] = suffix[u][i + 1];
if (int v = g[u][i + 1]; v != p) {
suffix[u][i] = (ll) suffix[u][i] * (f[v] + 1) % m;
}
}
}}]{
dfs(dfs, 0, -1);
}();
std::vector h(n, 1);
[&, dfs{[&](auto &&self, int u, int p, int pid) -> void {
if (~p) {
h[u] = ((ll) h[u] + (ll) h[p] * prefix[p][pid] % m * suffix[p][pid] % m) % m;
}
for (int i = 0; i < (int) g[u].size(); i++) if (int v = g[u][i]; v != p) {
self(self, v, u, i);
}
}}]{
dfs(dfs, 0, -1, -1);
}();
for (int i = 0; i < n; i++) {
std::cout << (ll) f[i] * h[i] % m << '\n';
}
return 0;
}
Intervals#
Tower#
Grid 2#
同 Grid 1,但给出所有障碍点的坐标。
障碍点数
。
很容易计算出没有任何障碍点的答案,即从
只需要将障碍部分都减去。不用担心减重了,由容斥原理可知许多项实际上被减去、抵消、减去、抵消…… 即用
展开代码
#include <bits/stdc++.h>
using ll = long long;
int main() {
std::cin.tie(nullptr)->sync_with_stdio(false);
int h, w, n;
std::cin >> h >> w >> n;
std::vector p(n, std::pair{0, 0});
for (auto &[x, y] : p) {
std::cin >> x >> y;
x -= 1, y -= 1;
}
p.emplace_back(h - 1, w - 1);
const int N = 200001;
const int mod = 1000000007;
std::vector<int> fac(N, 0), inv(N, 0), ifc(N, 0);
fac[0] = fac[1] = inv[0] = inv[1] = ifc[0] = ifc[1] = 1;
for (int i = 2; i < N; i++) {
fac[i] = (ll) fac[i - 1] * i % mod;
inv[i] = ((ll) mod - mod / i) % mod * inv[mod % i] % mod;
ifc[i] = (ll) ifc[i - 1] * inv[i] % mod;
}
auto binom = [&](int n, int m) -> ll {
if (n < m || m < 0) return 0ll;
return (ll) fac[n] * ifc[m] % mod * ifc[n - m] % mod;
};
std::vector f(n + 1, 0);
std::sort(p.begin(), p.end());
for (int i = 0; i < n + 1; i++) {
auto [x, y] = p[i];
f[i] = binom(x + y, x);
for (int j = 0; j < i; j++) {
auto [nx, ny] = p[j];
if (x >= nx && y >= ny) {
f[i] = ((ll) f[i] - (ll) f[j] * binom(x - nx + y - ny, x - nx) % mod + mod) % mod;
}
}
}
std::cout << f[n] << '\n';
return 0;
}
Frog 3#
作者:patricky
出处:https://www.cnblogs.com/patricky/p/train-20230420.html
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异