zoukankan      html  css  js  c++  java
  • 校内训练 2019-10-04

    这一场的 T1T2 有点简单,大概是 D1T1 和 D1T2 的难度。

    T3 的奇怪的条件看上去就没有任何想法。(2) 的整次幂的条件,可以暗示很多算法,比如二进制分组、倍增、分治等。但是每一种似乎都无法使用。大约比 D2T2 的难度要大一些吧。

    最后 T3 的标算的想法也很妙。通过发现最大度数为 (1) 的点集一定可以用 (1) 中颜色覆盖,从而想到分治的思路。


    T1. cipele

    题库传送门

    http://192.168.21.187/contest/32/problem/1 = http://192.168.21.187/problem/1313

    http://47.100.137.146/contest/32/problem/1 = http://47.100.137.146/problem/1313

    题解

    排序+二分+贪心+双指针。

    没什么好说的。

    #include<bits/stdc++.h>
    
    #define fec(i, x, y) (int i = head[x], y = g[i].to; i; i = g[i].ne, y = g[i].to)
    #define dbg(...) fprintf(stderr, __VA_ARGS__)
    #define File(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
    #define fi first
    #define se second
    #define pb push_back
    
    template<typename A, typename B> inline char smax(A &a, const B &b) {return a < b ? a = b, 1 : 0;}
    template<typename A, typename B> inline char smin(A &a, const B &b) {return b < a ? a = b, 1 : 0;}
    
    typedef long long ll; typedef unsigned long long ull; typedef std::pair<ll, int> pii;
    
    template<typename I> inline void read(I &x) {
    	int f = 0, c;
    	while (!isdigit(c = getchar())) c == '-' ? f = 1 : 0;
    	x = c & 15;
    	while (isdigit(c = getchar())) x = (x << 1) + (x << 3) + (c & 15);
    	f ? x = -x : 0;
    }
    
    const int N = 1e5 + 7;
    
    int n, m;
    int a[N], b[N];
    
    inline bool check(const int &mid) {
    	for (int i = 1, j = 1; i <= n; ++i) {
    		while (j < m && a[i] - b[j] > mid) ++j;
    		if (j > m || std::abs(a[i] - b[j]) > mid) return 0;
    		++j;
    	}
    	return 1;
    }
    
    inline void work() {
    	if (n > m) {
    		std::swap(n, m);
    		for (int i = 1; i <= m; ++i) std::swap(a[i], b[i]);
    	}
    	std::sort(a + 1, a + n + 1);
    	std::sort(b + 1, b + m + 1);
    	int l = 0, r = std::max(a[n] - b[1], b[m] - a[1]);
    	while (l < r) {
    		int mid = (l + r) >> 1;
    		if (check(mid)) r = mid;
    		else l = mid + 1;
    	}
    	printf("%d
    ", l);
    }
    
    inline void init() {
    	read(n), read(m);
    	for (int i = 1; i <= n; ++i) read(a[i]);
    	for (int i = 1; i <= m; ++i) read(b[i]);
    //	dbg("**********
    ");
    }
    
    int main() {
    #ifdef hzhkk
    	freopen("hkk.in", "r", stdin);
    #else
    	File(cipele);
    #endif
    	init();
    	work();
    	fclose(stdin), fclose(stdout);
    	return 0;
    }
    

    T2. strah

    题目传送门

    http://192.168.21.187/contest/32/problem/2 = http://192.168.21.187/problem/1314

    http://47.100.137.146/contest/32/problem/2 = http://47.100.137.146/problem/1314

    题解

    首先把题目转化成所有矩形的覆盖格子总数。

    我们考虑统计所有以 ((i, j)) 为右上角的矩形的贡献。我们令 (a_j) 表示从 ((i, j)) 这个点向下,有多少个适合种草莓的格子。

    那么,以 ((i, j_1)) 为左上角,((i, j_2)) 为右上角的矩形的最大高度为 (min{a_jmid j_1 leq j leq j_2 })。另外,一个长度为 (l)最大高度为 (h) 的矩形,它的的总贡献是 (frac{h(h+1)l}{2})

    在统计所有以 ((i, j)) 为右上角的矩形的贡献时,可以发现对于 (j_1 leq j) 的矩形,最大高度被分成了很多段,每一段的内容就是目前的后缀最小值。

    显然这个可以用单调栈维护。

    #include<bits/stdc++.h>
    
    #define fec(i, x, y) (int i = head[x], y = g[i].to; i; i = g[i].ne, y = g[i].to)
    #define dbg(...) fprintf(stderr, __VA_ARGS__)
    #define File(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
    #define fi first
    #define se second
    #define pb push_back
    
    template<typename A, typename B> inline char smax(A &a, const B &b) {return a < b ? a = b, 1 : 0;}
    template<typename A, typename B> inline char smin(A &a, const B &b) {return b < a ? a = b, 1 : 0;}
    
    typedef long long ll; typedef unsigned long long ull; typedef std::pair<ll, int> pii;
    
    template<typename I> inline void read(I &x) {
    	int f = 0, c;
    	while (!isdigit(c = getchar())) c == '-' ? f = 1 : 0;
    	x = c & 15;
    	while (isdigit(c = getchar())) x = (x << 1) + (x << 3) + (c & 15);
    	f ? x = -x : 0;
    }
    
    const int N = 2e3 + 7;
    
    int n, m;
    int a[N], q[N];
    char s[N][N];
    
    inline void work() {
    	for (int j = 1; j <= m; ++j)
    		for (int i = 1; i <= n && s[i][j]; ++i) ++a[j];
    	ll ans = 0;
    	for (int i = 1; i <= n; ++i) {
    		ll sum = 0, hs = 0;
    		int tl = 0;
    		for (int j = 1; j <= m; ++j) {
    			while (tl && a[j] <= a[q[tl]]) sum -= (a[q[tl]] + 1ll) * a[q[tl]] / 2 * (j - q[tl] + j - 1ll - q[tl - 1]) * (q[tl] - q[tl - 1]) / 2, hs -= (a[q[tl]] + 1ll) * a[q[tl]] / 2 * (q[tl] - q[tl - 1]), --tl;
    			hs += (a[j] + 1ll) * a[j] / 2 * (j - q[tl]), sum += (a[j] + 1ll) * a[j] / 2 * (1 + j - 1ll - q[tl]) * (j - q[tl] - 1) / 2, q[++tl] = j;
    			sum += hs, ans += sum;
    //			dbg("i = %d, j = %d, a[j] = %d, sum = %lld, hs = %lld
    ", i, j, a[j], sum, hs);
    		}
    		
    		for (int j = 1; j <= m; ++j) --a[j];
    		for (int j = 1; j <= m; ++j) if (!s[i][j]) {
    			a[j] = 0;
    			for (int k = i + 1; k <= n && s[k][j]; ++k) ++a[j];
    		}
    	}
    	printf("%lld
    ", ans);
    }
    
    inline void init() {
    	scanf("%d%d", &n, &m);
    	for (int i = 1; i <= n; ++i) {
    		scanf("%s", s[i] + 1);
    		for (int j = 1; j <= m; ++j) s[i][j] = s[i][j] == '.';
    	}
    }
    
    int main() {
    #ifdef hzhkk
    	freopen("hkk.in", "r", stdin);
    #else
    	File(strah);
    #endif
    	init();
    	work();
    	fclose(stdin), fclose(stdout);
    	return 0;
    }
    

    T3. teoreticar

    题目传送门

    http://192.168.21.187/contest/32/problem/3 = http://192.168.21.187/problem/1315

    http://47.100.137.146/contest/32/problem/3 = http://47.100.137.146/problem/1315

    题解

    (C) 为这个二分图的所有点的最大度数

    如果 (C = 1),很容易发现只需要 (1) 中颜色即可完成染色。

    如果 (C > 1),那么我们考虑把这个二分图的边集分成两部分,每一部分的点的最大度数都不超过 (lceil frac C2 ceil)。对于二分图中的一个环,因为是二分图,所以环长一定为偶数,又因为环中每一个点一定连接两条边,所以我们在环上间隔着分组。即第一条便分到第一组,第二条边分到第二组,第三条边分到第三组……

    如果还有一些不成环的东西形成了一棵树。当然我们对于树的话可以随便分,只需要保持一个点的所有出边都被均匀地分到了两组即可。不过为了方便,我们考虑把二分图中左边的所有的度数为奇数的点向一个虚点连边,右边的度数为奇数的点向另一个虚点连边。如果虚点的度数为奇数,那么就把两个虚点之间再连一条边。这样,这个图中就全部是环了,可以直接用上面的方法分组。

    这样,任何一个点的出边都被均匀地分到了两个组中。对于度数为奇数的点,由于虚边的存在,所以可能不均匀,因此分治以后的最大度数需要加上上取整符号,即 (lceil frac C2 ceil)

    从这个算法中可以看出,我们求得的答案不超过 (2^{lceillog_2C ceil})。又由于标准答案肯定不会小于 (C),所以我们求得的答案符合题意。

    事实上,我们可以证明,标准答案一定恰好等于 (C),即二分图中最大度数。但是这个结论对于解决这个题目没有帮助,所以感兴趣的同学可以参考 EI 神仙的博客:https://blog.csdn.net/EI_Captain/article/details/89408037

    #include<bits/stdc++.h>
    
    #define fec(i, x, y) (int i = head[x], y = g[i].to; i; i = g[i].ne, y = g[i].to)
    #define dbg(...) fprintf(stderr, __VA_ARGS__)
    #define File(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
    #define fi first
    #define se second
    #define pb push_back
    
    template<typename A, typename B> inline char smax(A &a, const B &b) {return a < b ? a = b, 1 : 0;}
    template<typename A, typename B> inline char smin(A &a, const B &b) {return b < a ? a = b, 1 : 0;}
    
    typedef long long ll; typedef unsigned long long ull; typedef std::pair<int, int> pii;
    
    template<typename I> inline void read(I &x) {
    	int f = 0, c;
    	while (!isdigit(c = getchar())) c == '-' ? f = 1 : 0;
    	x = c & 15;
    	while (isdigit(c = getchar())) x = (x << 1) + (x << 3) + (c & 15);
    	f ? x = -x : 0;
    }
    
    const int N = 2e5 + 7;
    const int M = 5e5 + 7;
    
    int n, nl, nr, m, tcl = 2;
    int deg[N], ans[M], vis[N], bl[M << 1];
    
    struct Edges { int x, y, id; } c[M], d1[M], d2[M];
    
    struct Edge { int to, ne, w; } g[M << 1]; int head[N], tot;
    inline void addedge(int x, int y, int z) { g[++tot].to = y, g[tot].w = z, g[tot].ne = head[x], head[x] = tot; }
    inline void adde(int x, int y, int z) { addedge(x, y, z), addedge(y, x, z); }
    
    inline void dfs(int x, int fa = 0) {
    	for fec(i, x, y) if (y != fa && !bl[g[i].w]) {
    		bl[g[i].w] = tcl ^= 1;//, dbg("nxt: %d %d %d
    ", x, y, tcl);
    		head[x] = g[i].ne; dfs(y, x); return;
    	}
    }
    
    inline void calc(int l, int r) {
    	tot = vis[n + 1] = vis[n + 2] = head[n + 1] = head[n + 2] = 0;
    //	memset(bl, 0, sizeof(bl));
    //	memset(head, 0, sizeof(head));
    //	memset(deg, 0, sizeof(deg));
    	for (int i = l; i <= r; ++i) head[c[i].x] = head[c[i].y] = deg[c[i].x] = deg[c[i].y] = vis[c[i].x] = vis[c[i].y] = bl[c[i].id] = 0;
    	for (int i = l; i <= r; ++i) adde(c[i].x, c[i].y, c[i].id), ++deg[c[i].x], ++deg[c[i].y];//, dbg("edges: %d %d
    ", c[i].x, c[i].y);
    	int mm = m, mxd = 0, dd = 0;
    	for (int i = l; i <= r; ++i) {
    		smax(mxd, deg[c[i].x]), smax(mxd, deg[c[i].y]);
    //		if (deg[c[i].x] == mxd) dbg("*** mxd: x = %d
    ", c[i].x);
    //		if (deg[c[i].y] == mxd) dbg("*** mxd: y = %d
    ", c[i].y);
    		if (deg[c[i].x] & 1) adde(c[i].x, n + 1, ++mm), ++dd;
    		if (deg[c[i].y] & 1) adde(c[i].y, n + 2, ++mm);
    		deg[c[i].x] = deg[c[i].y] = 0;
    	}
    //	dbg("l = %d, r = %d, mxd = %d
    ", l, r, mxd);
    	if (dd & 1) adde(n + 1, n + 2, ++mm);
    	
    	if (mxd == 1) {
    		++ans[0];
    		for (int i = l; i <= r; ++i) ans[c[i].id] = ans[0];
    		return;
    	}
    	
    //	memset(bl, 0, sizeof(bl));
    	for (int i = m + 1; i <= mm; ++i) bl[i] = 0;
    	for (int i = l; i <= r; ++i) if (!vis[c[i].x]) dfs(c[i].x);
    //	dbg("******************************
    ");
    	int totl = 0, totr = 0, tot = l - 1;
    	for (int i = l; i <= r; ++i) if (/*dbg("bl[c[%d].id] = %d
    ", i, bl[c[i].id]), */bl[c[i].id] == 2) d1[++totl] = c[i]; else d2[++totr] = c[i];
    	for (int i = 1; i <= totl; ++i) c[++tot] = d1[i];
    	for (int i = 1; i <= totr; ++i) c[++tot] = d2[i];
    	calc(l, l + totl - 1), calc(l + totl, r);
    }
    
    inline void work() {
    	calc(1, m);
    	printf("%d
    ", ans[0]);
    	for (int i = 1; i <= m; ++i) printf("%d
    ", ans[i]);
    }
    
    inline void init() {
    	read(nl), read(nr), read(m);
    	n = nl + nr;
    	int x, y;
    	for (int i = 1; i <= m; ++i) read(x), read(y), c[i] = (Edges){ x, y + nl, i };
    }
    
    int main() {
    #ifdef hzhkk
    	freopen("hkk.in", "r", stdin);
    #else
    	File(teoreticar);
    #endif
    	init();
    	work();
    	fclose(stdin), fclose(stdout);
    	return 0;
    }
    
  • 相关阅读:
    vagrantfile 示例
    服务器raid查看
    redis 使用记录
    golang 典型并发任务
    percona-server-mongodb 通用二进制下载
    命令之iperf-服务器之间网络测速
    用awk在命令行处理分析日志
    python是解释型还是编译型
    使用github action发布python包到Pypi
    算法图解学习系列--第6章--广度优先搜索算法BFS
  • 原文地址:https://www.cnblogs.com/hankeke/p/contest20191004.html
Copyright © 2011-2022 走看看