• ICPC 2019-2020 North-Western Russia Regional Contest


    Contest Info

    Practice Link

    Solved A B C D E F G H I J K L M
    8/13 O O - - O - - O O O Ø - O
    • O 在比赛中通过
    • Ø 赛后通过
    • ! 尝试了但是失败了
    • - 没有尝试

    Solutions

    Problem A. Accurate Movement

    签到题。

    代码:

    view code
    #include <bits/stdc++.h>
    using namespace std;
    int ceil(int x, int y) {
    	return (x + y - 1) / y;
    }
    
    int main() {
    	int a, b, n;
    	while (scanf("%d%d%d", &a, &b, &n) != EOF) {
    		int res = ceil(n - b, b - a) + ceil(n - a, b - a);
    		printf("%d
    ", res);
    	}
    	return 0;
    }
    

    Problem B. Bad Treap

    题意:
    令Treap的一对二维点权为((f, sin(x))),现在要给出(n)(x),使得这个Treap的深度最大

    思路:
    考虑很小的时候,(x = sin(x)),那么它两维都是单调的,深度最大

    代码:

    view code
    #include <bits/stdc++.h>
    
    using namespace std;
    
    int main() {
    	int n;
    	scanf("%d", &n);
    	for (long long i = 1; i <= n; ++i)
    		printf("%lld
    ", i * 710 - 710 * 25000);
    	return 0;
    }
    

    Problem E. Equidistant

    题意:
    给出一棵树,再给定(m)个点,现在要找一个点,使得这个点到(m)个点的距离相等

    思路:
    (m)个点作为起点跑多源最短路,但是同时要记录到点(x)的最短路径条数,当最短路径条数为(m)的时候,那么这个点就是合法的

    代码:

    view code
    #include <bits/stdc++.h>
    
    using namespace std;
    
    const int N = 2e5 + 10;
    
    int n, m;
    int dep[N], sze[N], a[N], vis[N];
    vector<vector<int> >G;
    
    void gao() {
    	queue<int> q;
    	for (int i = 1; i <= m; ++i) q.push(a[i]);
    	while (!q.empty()) {
    		int u = q.front();
    		q.pop();
    		for (auto &v : G[u]) {
    			if (dep[v] == 0 || dep[v] == dep[u] + 1) {
    				dep[v] = dep[u] + 1;
    				sze[v] += sze[u];
    				if (sze[v] == m) {
    					printf("YES
    %d
    ", v);
    					return ;
    				}
    				if (!vis[v]) {
    					q.push(v);
    					vis[v] = 1;
    				}
    			}
    		}
    	}
    	puts("NO");
    }
    
    int main() {
    	while (scanf("%d %d", &n, &m) != EOF) {
    		G.clear();
    		G.resize(n + 1);
    		memset(dep, 0, sizeof dep);
    		memset(sze, 0, sizeof sze);
    		memset(vis, 0, sizeof vis);
    		for (int i = 1, u, v; i < n; ++i) {
    			scanf("%d %d", &u, &v);
    			G[u].push_back(v);
    			G[v].push_back(u);
    		}
    		for (int i = 1; i <= m; ++i) {
    			scanf("%d", a + i);
    			dep[a[i]] = 1;
    			sze[a[i]] = 1;
    			vis[a[i]] = 1;
    		}
    		if (n == 1) {
    			puts("YES
    1");
    		} else {
    			gao();
    		}
    	}
    	return 0;
    }
    

    Problem H. High Load Database

    题意:
    给出(n)个数(a_i(sum a_i leq 10^6))(q)次询问给出一个(t_i),问将这(n)个数分成若干个连续段,使得每段之和不超过(t_i)的最小段数

    思路:
    考虑单次询问显然可以贪心合并,但是我们可以维护一个前缀和,每次二分跳下一个位置,所以处理一个询问的时间是(O( ext{段数}logn))
    并且考虑(sum a_i leq 10^6),所以所有可行询问的总段数不会很多,直接暴力即可。

    代码:

    view code
    #include <bits/stdc++.h>
    using namespace std;
    const int N = 1e6 + 10;
    int n, q, Max, a[N], sum[N], ans[N], vis[N]; 
    
    int getans(int limit) {
    	if (vis[limit]) return ans[limit];
    	vis[limit] = 1;
    	if (Max > limit) {
    		return ans[limit] = -1;
    	}
    	if (limit <= 1000) {
    		int res = 1, pre = 0;
    		for (int i = 1; i <= n; ++i) {
    			if (a[i] + pre <= limit) {
    				pre += a[i];
    			} else {
    				pre = a[i];
    				++res;
    			}
    		}
    		return ans[limit] = res;
    	} else {
    		int res = 0, pos = 0;
    		while (pos < n) {
    			++res;
    			int nx = upper_bound(sum + 1, sum + 1 + n, limit + sum[pos]) - sum - 1;
    			pos = nx; 
    		}
    		return ans[limit] = res;
    	}
    }
    
    int main() {
    	while (scanf("%d", &n) != EOF) {
    		memset(vis, 0, sizeof vis);
    		sum[0] = 0;
    		for (int i = 1; i <= n; ++i) {
    			scanf("%d", a + i);
    			Max = max(Max, a[i]);	
    			sum[i] = sum[i - 1] + a[i];
    		}
    		scanf("%d", &q);
    		while (q--) {
    			int need; scanf("%d", &need);
    			int res = getans(need);
    			if (res == -1) puts("Impossible");
    			else printf("%d
    ", res);
    		}
    	}
    	return 0;
    }
    

    Problem I. Ideal Pyramid

    代码:

    view code
    #include <bits/stdc++.h>
    
    using namespace std;
    
    const int N = 1e5 + 10;
    const int INF = 0x3f3f3f3f;
    
    struct node {
    	int x, y, z;
    
    	node() {}
    
    	node(int x, int y, int z): x(x), y(y), z(z) {}
    }a[N];
    
    int n;
    int x, y;
    
    bool ok(int h) {
    	int l = -INF, r = INF, u = INF, d = -INF;
    	for (int i = 1; i <= n; ++i) {
    		if (h < a[i].z) return false;
    		int x = h - a[i].z;
    		l = max(l, a[i].x - x);
    		r = min(r, a[i].x + x);
    		u = min(u, a[i].y + x);
    		d = max(d, a[i].y - x);
    	}
    	if (l > r || d > u) return false;
    	x = l, y = d;
    	return true;
    }
    
    int main() {
    	while (scanf("%d", &n) != EOF) {
    		for (int i = 1; i <= n; ++i) {
    			scanf("%d %d %d", &a[i].x, &a[i].y, &a[i].z);
    		}
    		int l = 0, r = INF, res = INF;
    		x = INF, y = INF;
    		while (r - l >= 0) {
    			int mid = (l + r) >> 1;
    			if (ok(mid)) {
    				r = mid -1;
    				res = mid;
    			} else {
    				l = mid + 1;
    			}
    		}
    		ok(res);
    		printf("%d %d %d
    ", x, y, res);
    	}
    	return 0;
    }
    

    Problem J. Just the Last Digit

    题意:
    有一个(n)个点的有向图,(i)(j)有边,那么必然有(i < j)
    现在给出(a_{i, j} = i ightarrow j)的路径条数模(10)的结果,要你还原这个图。

    思路:
    正着推,考虑新加入一个点(k)的时候,我们枚举一个点(i(i < k)),如果(i)(k)通过点(j(i < j < k))中转的路径之和模(10)不等于(a_{i, j}),那么(i ightarrow k)这条边是存在的,否则不存在

    代码:

    view code
    #include <bits/stdc++.h>
    
    using namespace std;
    
    typedef long long ll;
    
    const int N = 510;
    
    int n;
    char a[N][N];
    int res[N][N];
    
    int main() {
    	while (scanf("%d", &n) != EOF) {
    		memset(res, 0, sizeof res);
    		for (int i = 1; i <= n; ++i) {
    			for (int j = 1; j <= n; ++j) {
    				scanf(" %c", &a[i][j]);
    			}
    		}
    		for (int i = 1; i <= n; ++i) {
    			for (int j = i + 1; j <= n; ++j) {
    				int sum = 0;
    				for (int k = i + 1; k < j; ++k) {
    					if (res[i][k]) sum += a[k][j] - '0';
    				}
    				if ((sum + 1) % 10 == a[i][j] - '0') res[i][j] = 1;
    			}
    		}
    		for (int i = 1; i <= n; ++i) {
    			for (int j = 1; j <= n; ++j) {
    				printf("%d", res[i][j]);
    			}
    			puts("");
    		}
    	}
    	return 0;
    }
    

    Problem K. King’s Children

    题意:
    给出一个(n cdot m)的矩形,上面的'.'表示空地,字母表示国王的儿子,'A'表示大儿子。
    现在要给每个儿子划分城市,每个城市必须是一个矩形,每块空地只能属于一个城市,一个城市里面只能包含一个儿子。
    但是大儿子划分得到的空地数量要尽可能的多,但不一定是最多。

    思路:
    对'A'找一个极大子矩形,挖空后将剩下的分完。
    考虑两种分法:

    • 先竖向扩展,然后横向扩展
    • 先横向扩展,然后竖向扩展

    这两种分法不可能同时不成立,不太知道为啥(猜的)。。

    代码:

    view code
    #include <bits/stdc++.h>
    using namespace std;
    #define dbg(x...) do { cout << "33[32;1m" << #x << " -> "; err(x); } while(0)
    void err() { cout << "33[39;0m" << endl; }
    template <class T, class... Ts> void err(const T&arg, const Ts&... args) { cout << arg << " "; err(args...); }
    const int N = 1e3 + 10;
    const int INF = 0x3f3f3f3f;
    int n, m, ax, ay;
    char str[N][N], stra[N][N], strb[N][N];
    int up[N][N], down[N][N];
    int X[N], Y[N];
    
    void gaoA(char str[][N], int l, int r) {
    	int MinU = INF, MinD = INF;
    	for (int i = l; i <= r; ++i) {
    		MinU = min(MinU, up[ax][i]);
    		MinD = min(MinD, down[ax][i]);
    	}
    	for (int i = l; i <= r; ++i) {
    		for (int j = 1; j <= MinU; ++j) {
    			str[ax - j + 1][i] = 'a';
    		}
    		for (int j = 1; j <= MinD; ++j) {
    			str[ax + j - 1][i] = 'a';
    		}
    	}
    	str[ax][ay] = 'A';
    }
    
    void gaoU(char str[][N]) {
    	for (int i = 1; i <= n; ++i) {
    		for (int j = 1; j <= m; ++j) {
    			if (str[i][j] > 'A' && str[i][j] <= 'Z') {
    				up[i][j] = i;
    				for (int o = 1; ; ++o) {
    					if (i - o < 1) break;
    					if (str[i - o][j] != '.') break;
    					up[i][j] = i - o;
    					str[i - o][j] = str[i][j] - 'A' + 'a';
    				}
    			}	
    		}
    	}
    }
    
    void gaoD(char str[][N]) {
    	for (int i = 1; i <= n; ++i) {
    		for (int j = m; j >= 1; --j) {
    			if (str[i][j] > 'A' && str[i][j] <= 'Z') {
    				down[i][j] = i;
    				for (int o = 1; ; ++o) {
    					if (i + o > n) break;
    					if (str[i + o][j] != '.') break;
    					down[i][j] = i + o;
    					str[i + o][j] = str[i][j] - 'A' + 'a'; 
    				}
    			}
    		}
    	}
    }
    
    void gaoL(char str[][N]) {
    	for (int j = 1; j <= m; ++j) {
    		for (int i = 1; i <= n; ++i) {
    			if (str[i][j] > 'A' && str[i][j] <= 'Z') {
    				for (int o = j - 1; o >= 1; --o) {
    					int F = 1;
    					for (int k = up[i][j]; k <= down[i][j]; ++k) { 
    						if (str[k][o] != '.') {
    							F = 0;
    							break;
    						}
    					}
    					if (!F) break;
    					for (int k = up[i][j]; k <= down[i][j]; ++k) {
    						str[k][o] = str[i][j] - 'A' + 'a';
    					}
    				}
    			}
    		}
    	}
    }
    
    void gaoR(char str[][N]) {
    	for (int j = m; j >= 1; --j) {
    		for (int i = 1; i <= n; ++i) { 
    			if (str[i][j] > 'A' && str[i][j] <= 'Z') { 
    				for (int o = j + 1; o <= m; ++o) { 
    					int F = 1; 
    					for (int k = up[i][j]; k <= down[i][j]; ++k) {
    						if (str[k][o] != '.') {
    							F = 0;
    							break;
    						}
    					}
    					if (!F) break;
    					for (int k = up[i][j]; k <= down[i][j]; ++k) {
    						str[k][o] = str[i][j] - 'A' + 'a';
    					}
    				}
    			}
    		}
    	}
    }
    
    
    void gaoU1(char str[][N]) {
    	for (int i = 1; i <= n; ++i) {
    		for (int j = 1; j <= m; ++j) {
    			if (str[i][j] > 'A' && str[i][j] <= 'Z') {
    				for (int o = i - 1; o >= 1; --o) {
    					int F = 1;
    					for (int k = up[i][j]; k <= down[i][j]; ++k) {
    						if (str[o][k] != '.') {
    							F = 0;
    							break;
    						}
    					}
    					if (!F) break;
    					for (int k = up[i][j]; k <= down[i][j]; ++k) {
    						str[o][k] = str[i][j] - 'A' + 'a';
    					}
    				}
    			}
    		}
    	}
    }
    
    void gaoD1(char str[][N]) {
    	for (int i = 1; i <= n; ++i) {
    		for (int j = 1; j <= m; ++j) {
    			if (str[i][j] > 'A' && str[i][j] <= 'Z') {
    				for (int o = i + 1; o <= n; ++o) {
    					int F = 1;
    					for (int k = up[i][j]; k <= down[i][j]; ++k) {
    						if (str[o][k] != '.') {
    							F = 0;
    							break;
    						}
    					}
    					if (!F) break;
    					for (int k = up[i][j]; k <= down[i][j]; ++k) {
    						str[o][k] = str[i][j] - 'A' + 'a';
    					}
    				}
    			}
    		}
    	}
    }
    
    void gaoL1(char str[][N]) { 
    	for (int j = 1; j <= m; ++j) {
    		for (int i = 1; i <= n; ++i) {
    			if (str[i][j] > 'A' && str[i][j] <= 'Z') {
    				up[i][j] = j; 
    				for (int o = 1; ; ++o) {
    					if (j - o < 1) break; 
    					if (str[i][j - o] != '.') break;
    					up[i][j] = j - o; 
    					str[i][j - o] = str[i][j] - 'A' + 'a';
    				}
    			}	
    		}
    	}
    }
    
    void gaoR1(char str[][N]) {
    	for (int j = m; j >= 1; --j) {
    		for (int i = 1; i <= n; ++i) {
    			if (str[i][j] > 'A' && str[i][j] <= 'Z') {
    				down[i][j] = j;
    				for (int o = 1; ; ++o) {
    					if (j + o > m) break;
    					if (str[i][j + o] != '.') break;
    					down[i][j] = j + o;
    					str[i][j + o] = str[i][j] - 'A' + 'a';
    				}
    			}
    		}
    	}
    }
    
    void print(char str[][N]) {
    	for (int i = 1; i <= n; ++i) printf("%s
    ", str[i] + 1);
    }
    
    bool ok(char str[][N]) {
    	for (int i = 1; i <= n; ++i) {
    		for (int j = 1; j <= m; ++j) {
    			if (str[i][j] == '.')
    				return false;
    		}
    	}
    	return true;
    }
    
    int main() {
    	while (scanf("%d %d", &n, &m) != EOF) {
    		for (int i = 1; i <= n; ++i) {
    			scanf("%s", str[i] + 1);
    		}
    		for (int i = 1; i <= n; ++i) {
    			for (int j = 1; j <= m; ++j) {
    				if (str[i][j] == 'A') {
    					ax = i, ay = j;
    				}
    			}
    		}
    		for (int i = 1; i <= n; ++i) {
    			for (int j = 1; j <= m; ++j) {
    				if (i == 1) {
    					if (str[i][j] == '.' || str[i][j] == 'A') up[i][j] = 1;
    					else up[i][j] = 0;
    				} else {
    					if (str[i][j] == '.' || str[i][j] == 'A') up[i][j] = up[i - 1][j] + 1;
    					else up[i][j] = 0;
    				}
    			}
    		}
    		for (int i = n; i >= 1; --i) {
    			for (int j = 1; j <= m; ++j) {
    				if (i == n) {
    					if (str[i][j] == '.' || str[i][j] == 'A') down[i][j] = 1;
    					else down[i][j] = 0;
    				} else {
    					if (str[i][j] == '.' || str[i][j] == 'A') down[i][j] = down[i + 1][j] + 1;
    					else down[i][j] = 0;
    				}
    			}
    		}
    		// get A size
    		int Max = -1, Maxl = -1 ,Maxr = -1;
    		for (int l = 1; l <= m; ++l) {
    			int MinU = INF, MinD = INF;
    			for (int r = l; r <= m; ++r) {
    				MinU = min(MinU, up[ax][r]);
    				MinD = min(MinD, down[ax][r]);
    				if (r >= ay && l <= ay) {
    					if (Max < (r - l + 1) * (MinU + MinD - 1)) {
    						Maxl = l, Maxr = r, Max = (r - l + 1) * (MinU + MinD - 1);
    					}
    				}
    			}
    		}
    		// color A size
    		gaoA(str, Maxl, Maxr);
    		for (int i = 1; i <= n; ++i) {
    			for (int j = 1; j <= m; ++j) {
    				stra[i][j] = str[i][j];
    				strb[i][j] = str[i][j];
    			}
    		}
    
    		gaoU(stra);
    		gaoD(stra);
    		gaoL(stra);
    		gaoR(stra);
    
    		gaoL1(strb);
    		gaoR1(strb);
    		gaoU1(strb);
    		gaoD1(strb);
    
    		if (ok(strb)) print(strb);
    		else if (ok(stra)) print(stra);
    		else assert(0);
    	}
    	return 0;
    }
    

    Problem M. Managing Difficulties

    签到题。

    代码:

    view code
    #include <bits/stdc++.h>
    using namespace std;
    using ll = long long;
    const int N = 2e3 + 10;
    int n, a[N];
    unordered_map <int, int> mp;
    
    int main() {
    	int _T; scanf("%d", &_T);
    	while (_T--) {
    		mp.clear();
    		scanf("%d", &n);
    		for (int i = 1; i <= n; ++i) scanf("%d", a + i);
    		ll res = 0;
    		for (int i = n; i >= 1; --i) ++mp[a[i]];
    		for (int i = 1; i <= n; ++i) {
    			--mp[a[i]];
    			for (int j = i - 1; j >= 1; --j) {
    				int x = 2 * a[i] - a[j];
    				if (mp.count(x)) {
    					res += mp[x];
    				}		
    			}
    		}
    		printf("%lld
    ", res);
    	}
    	return 0;
    }
    
  • 相关阅读:
    算法笔记_035:寻找最小的k个数(Java)
    (中级篇 NettyNIO编解码开发)第六章-编解码技术
    (入门篇 NettyNIO开发指南)第五章-分隔符和定长解码器使用
    (入门篇 NettyNIO开发指南)第四章-TIP黏包/拆包问题解决之道
    (入门篇 NettyNIO开发指南)第三章-Netty入门应用
    (基础篇 走进javaNIO)第二章-NIO入门
    (基础篇 走进javaNIO)第一章-java的i/o演进之路
    Apache Commons 工具类介绍及简单使用
    SimpleDateFormat使用和线程安全问题
    Calendar使用
  • 原文地址:https://www.cnblogs.com/Dup4/p/11968817.html
Copyright © 2020-2023  润新知