C. Equilateral Triangle
注意到等边三角形的每条边对应的弧一定也相等,那么如果圆的周长 \(L\) 不是 \(3\) 的倍数的话,就一定无解
令 \(r = \dfrac{L}{3}\)
固定点 \(x_a\),它可以和点 \(x_a+r\) 以及点 \(x_a+2r\) 构成等边三角形。然后利用乘法原理来算贡献即可
注意最后需要对答案除以 \(3\)
代码实现
#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, L;
cin >> n >> L;
vector<int> x(n);
rep(i, n-1) {
int d;
cin >> d;
x[i+1] = (x[i]+d)%L;
}
vector<int> cnt(L);
rep(i, n) cnt[x[i]]++;
if (L%3 != 0) {
puts("0");
return 0;
}
int r = L/3;
ll ans = 0;
rep(a, n) {
int x1 = (x[a]+r)%L;
int x2 = (x1+r)%L;
ans += (ll)cnt[x1]*cnt[x2];
}
ans /= 3;
cout << ans << '\n';
return 0;
}
D. String Rotation
为了保证字典序最小,所选区间的左端点一定是字符串最左边满足 \(S_i > S_{i+1}\) 的 \(i\),不妨记为 \(l\)
接下来我们要找区间右端点 \(r\),这其实等价于一直交换 \(S_l\) 和它右边的相邻字符,直到满足 \(S_l\) 小于它右边的相邻字符,这时就可以停下来了,此时 \(r\) 就是 当前 \(S_l\) 所在的位置
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
void solve() {
int n;
string s;
cin >> n >> s;
int l = -1;
rep(i, n-1) {
if (s[i] > s[i+1]) {
l = i;
break;
}
}
if (l != -1) {
for (int i = l; i < n-1; ++i) {
if (s[i] < s[i+1]) break;
swap(s[i], s[i+1]);
}
}
cout << s << '\n';
}
int main() {
int t;
cin >> t;
while (t--) solve();
return 0;
}
E. Pair Annihilation
容易发现将树上所有电子归并到树上任意一点的费用都是一样的
不妨取点 \(1\) 为根节点,我们可以将所有电子移动到根节点上
具体地,自底向上,将当前点上的电子转移给它的父节点
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using ll = long long;
struct Edge { // C++20特性,不需要写构造函数
int to, cost;
};
int main() {
int n;
cin >> n;
vector<int> x(n);
rep(i, n) cin >> x[i];
vector<vector<Edge>> g(n);
rep(i, n-1) {
int u, v, w;
cin >> u >> v >> w;
--u; --v;
g[u].emplace_back(v, w);
g[v].emplace_back(u, w);
}
ll ans = 0;
auto dfs = [&](auto& f, int v, int p=-1) -> int {
int tot = x[v];
for (auto [u, w] : g[v]) {
if (u == p) continue;
int r = f(f, u, v);
ans += (ll)w*abs(r);
tot += r;
}
return tot;
};
dfs(dfs, 0);
cout << ans << '\n';
return 0;
}
F. Connecting Points
用小根堆和并查集模拟即可
代码实现
#include <bits/stdc++.h>
#include <atcoder/all>
using namespace atcoder;
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
int main() {
int n, q;
cin >> n >> q;
using P = pair<int, int>;
using Edge = pair<int, P>;
priority_queue<Edge, vector<Edge>, greater<Edge>> pq;
vector<int> x, y;
auto add = [&](int nx, int ny) {
int v = x.size();
rep(i, x.size()) {
int dist = abs(nx-x[i]) + abs(ny-y[i]);
pq.emplace(dist, P(i, v));
}
x.push_back(nx);
y.push_back(ny);
};
rep(i, n) {
int nx, ny;
cin >> nx >> ny;
add(nx, ny);
}
dsu uf(n+q);
rep(qi, q) {
int type;
cin >> type;
if (type == 1) {
int nx, ny;
cin >> nx >> ny;
add(nx, ny);
}
else if (type == 2) {
while (pq.size()) {
auto [a, b] = pq.top().second;
if (!uf.same(a, b)) break;
pq.pop();
}
if (!pq.size()) {
puts("-1");
continue;
}
int k = pq.top().first;
cout << k << '\n';
while (pq.size() and pq.top().first == k) {
auto [a, b] = pq.top().second; pq.pop();
uf.merge(a, b);
}
}
else {
int u, v;
cin >> u >> v;
--u; --v;
if (uf.same(u, v)) puts("Yes");
else puts("No");
}
}
return 0;
}
G. Accumulation of Wealth
\(ans_k = \displaystyle\sum\limits_{i} \binom{n-1}{k-1} \cdot p^k(1-p)^{i-k} \cdot d_i\),其中 \(d_i = \displaystyle\prod\limits_{j=i+1}^{n-1} (1+\frac{1-p}{j+1})\)
然后将组合数拆开得到,
\(ans_k = \displaystyle\sum\limits_{i} \dfrac{(i-1)!}{(k-1)!(i-k)!} \cdot p^k(1-p)^{i-k} \cdot d_i\)
再将和 \(i\) 无关的项提出来,
\(
ans_k = \frac{p^k}{(k-1)!}\displaystyle\sum\limits_{i} \dfrac{(i-1)!}{(i-k)!} \cdot (1-p)^{i-k} \cdot d_i
\)
可以发现,这里的和式就是个卷积的形式,跑一遍 \(\operatorname{NTT}\) 即可
代码实现
#include <bits/stdc++.h>
#include <atcoder/all>
using namespace atcoder;
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using mint = modint998244353;
struct modinv {
int n; vector<mint> d;
modinv(): n(2), d({0,1}) {}
mint operator()(int i) {
while (n <= i) d.push_back(-d[mint::mod()%n]*(mint::mod()/n)), ++n;
return d[i];
}
mint operator[](int i) const { return d[i];}
} invs;
struct modfact {
int n; vector<mint> d;
modfact(): n(2), d({1,1}) {}
mint operator()(int i) {
while (n <= i) d.push_back(d.back()*n), ++n;
return d[i];
}
mint operator[](int i) const { return d[i];}
} facts;
struct modfactinv {
int n; vector<mint> d;
modfactinv(): n(2), d({1,1}) {}
mint operator()(int i) {
while (n <= i) d.push_back(d.back()*invs(n)), ++n;
return d[i];
}
mint operator[](int i) const { return d[i];}
} ifacts;
mint comb(int n, int k) {
if (n < k || k < 0) return 0;
return facts(n)*ifacts(k)*ifacts(n-k);
}
int main() {
int n; mint p, q;
{
int _p;
cin >> n >> _p;
p = _p;
}
p /= 100; q = mint(1)-p;
vector<mint> d(n);
d[n-1] = 1;
for (int i = n-2; i > 0; --i) {
d[i] = d[i+1]*(q/(i+1) + 1);
}
vector<mint> fi(n), fj(n);
for (int i = 1; i < n; ++i) fi[i] = d[i]*facts(i-1);
rep(j, n) fj[j] = ifacts(n-1-j)*q.pow(n-1-j);
auto fk = convolution(fi, fj);
rep(k, n) {
mint ans;
if (k == 0) {
ans = 1;
for (int i = 1; i < n; ++i) ans += q*ans*invs(i);
}
else {
ans = fk[k+(n-1)];
ans *= ifacts(k-1)*p.pow(k);
}
cout << ans.val() << ' ';
}
return 0;
}
浙公网安备 33010602011771号