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]);
	}
}
posted @ 2021-11-25 11:40  whx1003  阅读(175)  评论(0编辑  收藏  举报