A. Chess For Three
记录观众是哪一个,观众不能是赢家。
点击查看代码
void solve() {int n;std::cin >> n;std::vector<int> a(n);for (int i = 0; i < n; ++ i) {std::cin >> a[i];}int x = 1, y = 2, z = 3;for (int i = 0; i < n; ++ i) {if (a[i] == z) {std::cout << "NO\n";return;}if (a[i] == x) {std::swap(y, z);} else {std::swap(x, z);}}std::cout << "YES\n";
}
B. Beautiful Divisors
枚举。
点击查看代码
void solve() {int n;std::cin >> n;for (int i = n; i >= 1; -- i) {for (int j = 0; j < 10; ++ j) {if ((((1 << j) - 1) << (j - 1)) == i && n % i == 0) {std::cout << i << "\n";return;}}}
}
C. Rumor
题意:求每个联通块的最小值的和。
dfs求联通块即可。
点击查看代码
void solve() {int n, m;std::cin >> n >> m;std::vector<int> a(n);for (int i = 0; i < n; ++ i) {std::cin >> a[i];}std::vector<std::vector<int>> adj(n);for (int i = 0; i < m; ++ i) {int u, v;std::cin >> u >> v;-- u, -- v;adj[u].push_back(v);adj[v].push_back(u);}std::vector<int> st(n);int min = 2e9;auto dfs = [&](auto & self, int u) -> void {min = std::min(min, a[u]);st[u] = 1;for (auto & v : adj[u]) {if (!st[v]) {self(self, v);}}};i64 ans = 0;for (int i = 0; i < n; ++ i) {if (!st[i]) {min = 2e9;dfs(dfs, i);ans += min;}}std::cout << ans << "\n";
}
D. Credit Card
题意:一开始你有\(0\)元,每天会增加一些钱或者减少一些钱,或者询问当天的余额。你可以在任意一天充任意多的钱,你要保证任何时候余额都不超过\(d\),同时查询余额的时候余额不是负数。要求充钱次数最少。
如果我们需要充钱,那么最小把余额充到\(0\),最多充到\(d\)。那么我们可以维护一个上界和一个下界,每次查询的时候,如果需要充钱则把下界变为\(0\),上界变为\(d\)。其它情况就是两个值同时变化,如果上界大于\(d\),就变回\(d\),相当于我们在之前充钱的那一天少充一些,如果下界大于\(d\),则无解。
点击查看代码
void solve() {int n, d;std::cin >> n >> d;std::vector<int> a(n);for (int i = 0; i < n; ++ i) {std::cin >> a[i];}int ans = 0;i64 l = 0, r = 0;for (auto & x : a) {if (x == 0) {if (l < 0) {l = 0;}if (r < 0) {r = d;++ ans;}} else {l += x;r += x;if (l > d) {std::cout << -1 << "\n";return;}if (r > d) {r = d;}}}std::cout << ans << "\n";
}
E. Counting Arrays
题意:求长度为\(y\),乘积为\(x\)的序列有多少个,数组可以有负数。首先一个结论是,一个数的质因子不超过\(log_2n\)个。那么这个序列其它位置都是\(1\)。那么我们先对\(x\)质因数分解,那么对于每个因子,我们要把它们放到\(y\)个位置,每个位置可以为空,那么这就是插板法了。总共有\(C(cnt + y - 1, y - 1)\)种放法。每个质因子要单独考虑,因为不同质因子是不同的,而插板法要求每个元素没有区间。
然后考虑负数怎么放,显然\(x\)是正数,那么负数个数得是偶数个,那么对于\(y\)个数,我们选偶数个乘上\(-1\),,那么就是\(C(2, y) + C(4, y) + ...\),这个数是\(2^{y-1}\)次方。
代码省略取模类。
点击查看代码
struct Comb {int n;std::vector<Z> _fac;std::vector<Z> _invfac;std::vector<Z> _inv;Comb() : n{0}, _fac{1}, _invfac{1}, _inv{0} {}Comb(int n) : Comb() {init(n);}void init(int m) {if (m <= n) return;_fac.resize(m + 1);_invfac.resize(m + 1);_inv.resize(m + 1);for (int i = n + 1; i <= m; i++) {_fac[i] = _fac[i - 1] * i;}_invfac[m] = _fac[m].inv();for (int i = m; i > n; i--) {_invfac[i - 1] = _invfac[i] * i;_inv[i] = _invfac[i] * _fac[i - 1];}n = m;}Z fac(int m) {if (m > n) init(2 * m);return _fac[m];}Z invfac(int m) {if (m > n) init(2 * m);return _invfac[m];}Z inv(int m) {if (m > n) init(2 * m);return _inv[m];}Z binom(int n, int m) {if (n < m || m < 0) return 0;return fac(n) * invfac(m) * invfac(n - m);}
} comb;void solve() {int x, y;std::cin >> x >> y;Z ans = 1;for (int i = 2; i * i <= x; ++ i) {if (x % i == 0) {int n = 0;while (x % i == 0) {++ n;x /= i;}ans *= comb.binom(n + y - 1, y - 1);}}if (x > 1) {ans *= comb.binom(y, y - 1);}ans *= power<Z>(2, y - 1);std::cout << ans << "\n";
}