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\n", 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\n", 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\n%d\n", 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\n1");
		} 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(\text{段數}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\n", 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\n", x, y, res);
	}
	return 0;
}

Problem J. Just the Last Digit

題意:
有一個\(n\)個點的有向圖,\(i\)\(j\)有邊,那么必然有\(i < j\)
現在給出\(a_{i, j} = i \rightarrow j\)的路徑條數模\(10\)的結果,要你還原這個圖。

思路:
正着推,考慮新加入一個點\(k\)的時候,我們枚舉一個點\(i(i < k)\),如果\(i\)\(k\)通過點\(j(i < j < k)\)中轉的路徑之和模\(10\)不等於\(a_{i, j}\),那么\(i \rightarrow 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 << "\033[32;1m" << #x << " -> "; err(x); } while(0)
void err() { cout << "\033[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\n", 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\n", res);
	}
	return 0;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM