zoukankan      html  css  js  c++  java
  • 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]);
    	}
    }
    
  • 相关阅读:
    使用迭代器模式批量获得数据(C#实现)
    如何从技术上预防抢票软件刷屏
    如何用Tesseract做日文OCR(c#实现)
    我的.net开发百宝箱
    程序员必备基础:Git 命令全方位学习
    Java 异常处理的十个建议
    50道Java集合经典面试题(收藏版)
    记一次接口性能优化实践总结:优化接口性能的八个建议
    100道MySQL数据库经典面试题解析(收藏版)
    800+Java后端经典面试题,希望你找到自己理想的Offer呀~
  • 原文地址:https://www.cnblogs.com/whx1003/p/15601982.html
Copyright © 2011-2022 走看看