gym103427 部分题解
被阴间分块锤了/kk
(感觉这场质量不是特别高)
H
\(m\) 是偶数可以全选,否则可以必须断一条。
断的边可以是非割边或者割边但是两边都有偶数条边。
#include <cstdio>
#include <vector>
#include <algorithm>
constexpr int maxn = 2E+5 + 5;
int n, m, siz[maxn], ans = 1E+9;
std::vector<std::pair<int, int>> to[maxn];
int ind, dfn[maxn], low[maxn];
inline void DFS(int u, int fa) {
dfn[u] = low[u] = ++ind;
for(auto e : to[u]) if(e.first ^ fa) {
if(dfn[e.first]) {
low[u] = std::min(low[u], dfn[e.first]);
if(dfn[e.first] > dfn[u])
++siz[u], ans = std::min(ans, e.second);
}
else {
DFS(e.first, u), siz[u] += siz[e.first] + 1;
low[u] = std::min(low[u], low[e.first]);
if(low[e.first] != dfn[e.first] || !(siz[e.first] & 1))
ans = std::min(ans, e.second);
}
}
}
int main() {
scanf("%d%d", &n, &m);
long long ans0 = 0;
for(int i = 1, u, v, w; i <= m; ++i) {
scanf("%d%d%d", &u, &v, &w);
to[u].emplace_back(v, w);
to[v].emplace_back(u, w);
ans0 += w;
}
if(m & 1) DFS(1, 0), ans0 -= ans;
printf("%lld\n", ans0);
}
I
莫比乌斯变换保交比。
#include <cstdio>
#include <complex>
#include <iomanip>
#include <iostream>
using comp = std::complex<double>;
int T; comp z[4], w[4];
inline void getcomp(comp &x) {
double re, im;
scanf("%lf%lf", &re, &im);
x = comp(re, im);
}
int main() {
scanf("%d", &T);
while(T --> 0) {
getcomp(z[1]), getcomp(w[1]);
getcomp(z[2]), getcomp(w[2]);
getcomp(z[3]), getcomp(w[3]);
getcomp(z[0]);
if(z[0] == z[1]) { printf("%.10lf %.10lf\n", w[1].real(), w[1].imag()); continue; }
if(z[0] == z[2]) { printf("%.10lf %.10lf\n", w[2].real(), w[2].imag()); continue; }
if(z[0] == z[3]) { printf("%.10lf %.10lf\n", w[3].real(), w[3].imag()); continue; }
comp k = ((z[0] - z[1]) / (z[0] - z[2])) / ((z[3] - z[1]) / (z[3] - z[2])) * ((w[3] - w[1]) / (w[3] - w[2]));
w[0] = (k * w[2] - w[1]) / (k - comp(1, 0));
printf("%.10lf %.10lf\n", w[0].real(), w[0].imag());
}
}
K
阴间分块题。
对序列分块,然后每次要做的是先求出在这一块之前所有 \(\mathcal O(B^2)\) 个矩形的最大值,然后做 \(B\) 次矩形加,矩形求最大值。
第一部分可以每次做一遍扫描线维护历史最大值,第二部分可以离线 KDT,总复杂度 \(\mathcal O(\frac{m}{B}(B^2+m\log m))=\mathcal O(m\sqrt{m\log m})\)。
代码咕了。
L
容斥成钦定 \(k\) 条边的方案数,树形 dp 即可。
#include <cstdio>
#include <vector>
#include <algorithm>
using ll = long long;
constexpr ll mod = 998244353;
constexpr ll inv2 = (mod + 1) / 2;
constexpr int maxn = 4005;
inline ll fsp(ll a, ll b, ll res = 1) {
for(a %= mod; b; a = a * a % mod, b >>= 1)
b & 1 && (res = res * a % mod); return res;
}
int n, siz[maxn];
std::vector<int> to[maxn];
ll dp[maxn][maxn][2];
inline void DFS(int u, int fa) {
dp[u][0][0] = 1, siz[u] = 1;
for(int v : to[u]) if(v ^ fa) {
DFS(v, u);
static ll tmp[maxn][2];
for(int i = 0; i <= siz[u]; ++i)
for(int j = 0; j <= siz[v]; ++j) {
(tmp[i + j][0] += dp[u][i][0] * dp[v][j][0]) %= mod;
(tmp[i + j][0] += dp[u][i][0] * dp[v][j][1]) %= mod;
(tmp[i + j][1] += dp[u][i][1] * dp[v][j][0]) %= mod;
(tmp[i + j][1] += dp[u][i][1] * dp[v][j][1]) %= mod;
(tmp[i + j + 1][1] += dp[u][i][0] * dp[v][j][0]) %= mod;
}
siz[u] += siz[v];
for(int i = 0; i <= siz[u]; ++i) {
dp[u][i][0] = tmp[i][0], dp[u][i][1] = tmp[i][1];
tmp[i][0] = tmp[i][1] = 0;
}
}
}
inline ll sgn(int x) { return x & 1 ? -1 : 1; }
ll Fac[maxn], Inv[maxn], pw[maxn];
int main() {
scanf("%d", &n), n <<= 1;
for(int i = 1, u, v; i < n; ++i) {
scanf("%d%d", &u, &v);
to[u].push_back(v);
to[v].push_back(u);
}
DFS(1, 0);
Fac[0] = 1;
for(int i = 1; i <= n; ++i) Fac[i] = Fac[i - 1] * i % mod;
Inv[n] = fsp(Fac[n], mod - 2);
for(int i = n; i >= 1; --i) Inv[i - 1] = Inv[i] * i % mod;
pw[0] = 1;
for(int i = 1; i <= n; ++i) pw[i] = pw[i - 1] * inv2 % mod;
ll ans = 0;
for(int i = 0; i * 2 <= n; ++i)
(ans += sgn(i) * Fac[n - i * 2] * pw[n / 2 - i] % mod * Inv[n / 2 - i] % mod * (dp[1][i][1] + dp[1][i][0])) %= mod;
printf("%lld\n", (ans + mod) % mod);
}
M
考虑每次选择的一定是一个后缀,且下一次选择的是当前的一个 border 加上下一个字符。
根据 border 的结构,每个等差数列只需要一次统计,于是暴力枚举等差数列即可。
复杂度 \(\mathcal O(n\log n)\)。
#include <cstdio>
#include <cstring>
#include <algorithm>
constexpr int maxn = 1E+6 + 5;
char s[maxn], tmp[maxn];
int n, len, nxt[maxn];
inline void append(char c) {
tmp[++len] = c, tmp[len + 1] = 0;
int k = nxt[len - 1];
while(k && tmp[k + 1] != c) k = nxt[k];
if(k + 1 < len && tmp[k + 1] == c) ++k;
nxt[len] = k;
}
int main() {
scanf("%s", s + 1), n = strlen(s + 1);
for(int r = 1; r <= n; ++r) {
for(int k = len; ; k = nxt[k % (k - nxt[k]) + (k - nxt[k])]) {
if(s[r] > tmp[k + 1]) len = k;
if(!k) break;
}
printf("%d %d\n", r - len, r), append(s[r]);
}
}