zoukankan      html  css  js  c++  java
  • Codeforces Round #619 (Div. 2) 简要题解

    Codeforces Round #619 (Div. 2)

    A:只要每个位置都满足a[i] = c[i]或b[i] = c[i]即可。

    int main() {
    	int t; scanf("%d", &t);
    	while(t --) {
    		char a[110], b[110], c[110];
    		scanf("%s%s%s", a, b, c);
    		int n = strlen(a), tag = 1;
    		for(int i = 0; i < n; i ++) {
    			if(a[i] == c[i] || b[i] == c[i]) {
    				
    			} else {
    				tag = 0; break ;
    			}
    		}
    		puts(tag ? "YES" : "NO");
    	}
    	return 0;
    } 
    

    B:写了无脑二分,实际上可以线性:k取(max - min) / 2。max和min是与-1相邻的数中最大值和最小值。

    const int N = 4e5 + 10;
    const int mo = 1e9 + 7;
    int n, a[N], k;
    bool ck(int mid) {
    	ll l = 0, r = 1e9;
    	for(int i = 1; i <= n; i ++) if(~ a[i]) {
    		if(a[i + 1] == -1 || a[i - 1] == -1) {
    			ll nl = a[i] - mid, nr = a[i] + mid;
    			l = max(l, nl); r = min(r, nr);
    		}
    	}
    	if(l <= r) k = l;
    	return l <= r;
    }
    int main() {
    	int t; scanf("%d", &t);
    	while(t --) {
    		scanf("%d", &n);
    		for(int i = 1; i <= n; i ++) scanf("%d", a + i);
    		a[0] = a[n + 1] = 0;
    		int l = 0, r = 1e9, mid, ans;
    		for(int i = 1; i < n; i ++) if(~ a[i] && ~ a[i + 1])
    			l = max(l, a[i] > a[i + 1] ? a[i] - a[i + 1] : a[i + 1] - a[i]);
    		while(l <= r) {
    			mid = (l + r) >> 1;
    			if(ck(mid)) r = (ans = mid) - 1;
    			else l = mid + 1;
    		}
    		ck(ans);
    		printf("%d %d
    ", ans, k);
    	}
    	return 0;
    } 
    

    C:利用容斥思想化简式子,最后发现问题转换为:

    给定(x)(k),你需要安排(x_i)使得(sum_{i = 1}^k x_i = x),最小化(sum_{i = 1}^k x_i^2)

    结论是尽可能平均分。即令(y = lfloor frac{x}{k} floor)(x mod k)个元素为(y + 1),剩下为(y)

    简单的证明:假设最优方案中存在(x_i > x_j, x_i - x_j > 1),此时((x_i - 1)^2 + (x_j + 1)^2 = x_i^2 + x_j^2 + 2 (x_j - x_i + 1) < x_i^2 + x_j^2),说明有更优方案。

    int n, m;
    ll calc(ll n) {
    	return n * (n + 1) / 2;
    }
    ll __div(ll z, ll d) {
    	ll c = z / d, r = z % d;
    	return (c + 1) * (c + 1) * r + c * c * (d - r);
    }
    int main() {
    	int t; scanf("%d", &t);
    	while(t --) {
    		scanf("%d%d", &n, &m);
    		ll z = n - m, d = m + 1;
    		printf("%lld
    ", calc(n) - (z + __div(z, d)) / 2);
    	}
    	return 0;
    } 
    

    D:构造题,有方法把所有边都走一遍,构造方法见代码

    int n, m, k;
    vector< pair<string, int>  > ans;
    void push(string s, int t) {
    	if(t == 0) return ; 
    	static int x;
    	int sz = (int) s.size();
    	if(x + (ll) sz * t >= k) {
    		int d = k - x; string tmp;
    		if(d / sz > 0) ans.pb(mp(s, d / sz));
    		for(int i = 0; i < d % sz; i ++) tmp.pb(s[i]);
    		if(d % sz > 0) ans.pb(mp(tmp, 1));
    		printf("YES
    %d
    ", (int) ans.size());
    		for(auto y : ans) {
    			printf("%d %s
    ", y.sc, y.fs.c_str());
    		}
    		exit(0); 
    	}
    	ans.pb(mp(s, t)); x += sz * t;
    }
    int main() {
    	scanf("%d%d%d", &n, &m, &k);
    	for(int i = 1; i < n; i ++) {
    		push("RDU", m - 1);
    		push("L", m - 1);
    		push("D", 1);
    	}
    	push("R", m - 1);
    	push("L", m - 1);
    	push("U", n - 1);
    	puts("NO"); 
    	return 0;
    }
    

    E:标算是二维ST表,实际上冷静分析可以只需二维前缀和。首先我们发现了一个简单的结论,以某个点为左上角,最多有一个满足条件的正方形。

    那就直接f[len][i][j]表示(i, j)这个前缀矩形里有多少个点,以该点为左上角边长为len的正方形是合法的,询问就枚举长度用前缀和判断。

    复杂度(O(n^3 + qn)).

    const int N = 500 + 10;
    
    int n, m, q, sum[4][N][N], Map[N], f[N][N][N];
    char s[N][N];
    int query(int a[N][N], int x1, int y1, int x2, int y2) {
    	return a[x2][y2] - a[x1 - 1][y2] - a[x2][y1 - 1] + a[x1 - 1][y1 - 1];
    }
    bool judge(int x, int y, int l) {
    	int mx = x + (l / 2), my = y + (l / 2);
    	int sz = l * l / 4, ex = x + l - 1, ey = y + l - 1;
    	if(query(sum[0], x, y, mx - 1, my - 1) != sz) return 0;
    	if(query(sum[2], mx, y, ex, my - 1) != sz) return 0;
    	if(query(sum[1], x, my, mx - 1, ey) != sz) return 0;
    	if(query(sum[3], mx, my, ex, ey) != sz) return 0;
    	return 1;
    }
    int main() {
    	Map['R'] = 0; Map['G'] = 1; Map['Y'] = 2; Map['B'] = 3;
    	scanf("%d%d%d", &n, &m, &q);
    	for(int i = 1; i <= n; i ++) {
    		scanf("%s", s[i] + 1);
    		for(int j = 1; j <= m; j ++) {
    			sum[Map[s[i][j]]][i][j] = 1;
    		}
    	}
    	for(int k = 0; k < 4; k ++) {
    		for(int i = 1; i <= n; i ++) {
    			for(int j = 1; j <= m; j ++) {
    				sum[k][i][j] += sum[k][i - 1][j] + sum[k][i][j - 1] - sum[k][i - 1][j - 1];
    			}
    		}
    	}
    	for(int i = 1; i <= n; i ++) {
    		for(int j = 1; j <= m; j ++) if(s[i][j] == 'R') {
    			int lim = min(n - i + 1, m - j + 1);
    			for(int k = 2; k <= lim; k += 2) {
    				if(judge(i, j, k)) {
    					f[k][i][j] = 1; break ;
    				}
    			}
    		}
    	}
    	for(int k = 2; k <= max(n, m); k += 2) {
    		for(int i = 1; i <= n; i ++) {
    			for(int j = 1; j <= m; j ++) {
    				f[k][i][j] += f[k][i - 1][j] + f[k][i][j - 1] - f[k][i - 1][j - 1];
    			}
    		}
    	}
    	for(int i = 0; i < q; i ++) {
    		int x1, y1, x2, y2;
    		scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
    		int ans = 0, lim = min(x2 - x1 + 1, y2 - y1 + 1);
    		for(int k = 2; k <= lim; k += 2) {
    			int ex = x2 - k + 1, ey = y2 - k + 1;
    			if(query(f[k], x1, y1, ex, ey)) {
    				ans = k * k;
    			}
    		}
    		printf("%d
    ", ans);
    	}
    	return 0;
    } 
    

    F:做法又不同于标算,但其实大同小异。

    首先容易预处理d[x][y][col]表示((x, y))到最近的col颜色的点需要多少步。

    然后想象把颜色建成了一个图,图中每个颜色有一个出点和入点。图里c1的出点连到c2的入点,代价是最近的c1和c2格子的曼哈顿距离。

    在这张无向图上,c1出点到c2入点的最短路,表示的是起点你可以选定c1任意一点,终点你可以选c2任意一点,这两点的最短路。

    Floyd预处理(G[c1][c2])表示c1出点到c2入点的最短路。

    然后考虑询问,你移动的方式是行走->传送1->行走...->传送n->行走。首先不传送就是曼哈顿距离。然后你可以枚举传送1和传送n的颜色,假设是c1和c2,答案就是d[x1][y1][c1] + G[c1][c2] + d[x2][y2][c2] + 1 + [c1 != c2]。即你从(x1, y1)先走到c1的入点,然后走到c1出点,然后转移到c2的入点,然后转移到c2出点,最后转移到(x2, y2)。

    这说明了:你从(x1, y1)走到颜色c1下一步就是传送。会不会下一步是移动?若是移动到同颜色的位置再传送,显然不优。若是移动到其他颜色ci,那会在c1 = ci的时候被统计的。

    复杂度就是(O(k^3 + knm + q k^2))

    
    const int N = 40 + 4;
    const int M = 1004;
    const int INF = 1e8 + 10;
    
    const int dx[] = {1, 0, -1, 0};
    const int dy[] = {0, 1, 0, -1};
    int n, m, k, q, a[M][M], G[N][N], d[M][M][N];
    vector<pii> vec[N];
    void bfs(int col) {
    	queue<pii> q;
    	for(int i = 1; i <= n; i ++)
    		for(int j = 1; j <= m; j ++)
    			d[i][j][col] = -1;
    	for(pii u : vec[col]) {
    		q.push(u); d[u.fs][u.sc][col] = 0;
    	}
    	while(q.size()) {
    		pii u = q.front(); q.pop();
    		int t = a[u.fs][u.sc];
    		G[t][col] = G[col][t] = min(G[col][t], d[u.fs][u.sc][col]);
    		for(int i = 0; i < 4; i ++) {
    			pii v = mp(u.fs + dx[i], u.sc + dy[i]);
    			if(v.fs < 1 || v.fs > n || v.sc < 1 || v.sc > m) continue ;
    			if(-1 == d[v.fs][v.sc][col]) {
    				d[v.fs][v.sc][col] = d[u.fs][u.sc][col] + 1;
    				q.push(v);
    			}
    		}
    	}
    }
    int myabs(int x) {
    	return x > 0 ? x : -x;
    }
    int main() {
    	scanf("%d%d%d", &n, &m, &k);
    	for(int i = 1; i <= k; i ++)
    		fill(G[i] + 1, G[i] + k + 1, INF), G[i][i] = 0;
    	for(int i = 1; i <= n; i ++) {
    		for(int j = 1; j <= m; j ++) {
    			scanf("%d", &a[i][j]);
    			vec[a[i][j]].pb(mp(i, j));
    			if(i != 1 && a[i - 1][j] != a[i][j]) {
    				int u = a[i - 1][j], v = a[i][j];
    				G[u][v] = G[v][u] = 1;
    			}
    			if(j != 1 && a[i][j - 1] != a[i][j]) {
    				int u = a[i][j - 1], v = a[i][j];
    				G[u][v] = G[v][u] = 1;
    			}
    		}
    	}
    	for(int i = 1; i <= k; i ++) bfs(i);
    	for(int w = 1; w <= k; w ++)
    		for(int u = 1; u <= k; u ++)
    			for(int v = 1; v <= k; v ++)
    				G[u][v] = min(G[u][v], G[u][w] + G[w][v] + 1);
    	scanf("%d", &q);
    	for(int i = 1; i <= q; i ++) {
    		int x1, y1, x2, y2;
    		scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
    		int ans = myabs(x1 - x2) + myabs(y1 - y2);
    		for(int x = 1; x <= k; x ++) {
    			for(int y = 1; y <= k; y ++) {
    				ans = min(ans, d[x1][y1][x] + d[x2][y2][y] + G[x][y] + 1 + (x != y));
    			}
    		}
    		printf("%d
    ", ans);
    	}
    	return 0;
    }
    

    ps:本比赛模板代码

    #include <algorithm>
    #include <cstdlib>
    #include <cstring>
    #include <vector>
    #include <cstdio>
    #include <stack>
    #include <queue>
    #include <ctime>
    #include <set>
    using namespace std;
    
    #define fs first
    #define sc second
    #define pb push_back 
    typedef pair<int, int> pii;
    typedef double db;
    typedef long long ll;
    typedef long double ldb;
    typedef unsigned long long ull;
    
  • 相关阅读:
    Scrum Meeting Alpha
    Scrum Meeting Alpha
    Scrum Meeting Alpha
    你连自律都做不到,还奢谈什么自由?
    改变这个世界
    这世界没有人能随随便便成功
    “沙堆实验”
    解读那些年我们见过的“富人思维”
    心存希望,面朝大海
    闻香识女人 演讲台词
  • 原文地址:https://www.cnblogs.com/hongzy/p/12307242.html
Copyright © 2011-2022 走看看