ICPC 2019-2020 North-Western Russia Regional Contest 部分题解

E. Equidistant

题意:有一颗树,有 m m 个特殊点,问是否存在一个点到 m m 个特殊点的距离相等
解法:换根 d p dp 秒之,设 m x [ u ] , m n [ u ] mx[u],mn[u] 分别为 u u 子树中距离 u u 最远的特殊点的距离和最近的特殊点的距离,首先一次 d f s dfs 搞定树 d p dp ,接下来就是直接换根了,当一个点 u u 为根时 m x [ u ] = m n [ u ] mx[u]=mn[u] ,那么这个点一定是合法的点
#include<bits/stdc++.h>
#define pi pair<int, int>
#define mk make_pair
using namespace std;
const int maxn = 2e5 + 10, inf = 1e9;
vector<int> G[maxn];
vector<pi> s[maxn];
int mx[maxn], mn[maxn], cat[maxn], jie, n;
void dfs(int u, int fa) {
	if (cat[u])
		mx[u] = mn[u] = 0;
	else 
		mx[u] = -inf, mn[u] = inf;
	for (auto v : G[u])
		if (v != fa) {
			dfs(v, u);
			mx[u] = max(mx[u], mx[v] + 1);
			mn[u] = min(mn[u], mn[v] + 1);
		}
}
void dfs2(int u, int fa) {
	if (jie)
		return;
	if (cat[u])
		mx[u] = mn[u] = 0;
	else 
		mx[u] = -inf, mn[u] = inf;
	s[u].push_back(mk(mx[u],mn[u]));
	for (auto v : G[u]) {
		mx[u] = max(mx[u], mx[v] + 1);
		mn[u] = min(mn[u], mn[v] + 1);
		s[u].push_back(mk(mx[u], mn[u]));
	}
	if (mx[u] == mn[u]) {
		jie = u;
		return;
	}
	int Mx = -inf, Mn = inf;
	for (int i = G[u].size() - 1; ~i; i--) {
		int v = G[u][i];
		mx[u] = max(s[u][i].first, Mx);
		mn[u] = min(s[u][i].second, Mn);
		Mx = max(Mx, mx[v] + 1);
		Mn = min(Mn, mn[v] + 1);
		if (v != fa)
			dfs2(v, u);
	}
}
int main()
{
	int m, u, v;
	scanf("%d%d", &n, &m);
	for (int i = 1; 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", &u);
		cat[u] = v;
	}
	dfs(1, 0);
	dfs2(1, 0);
	if (jie)
		printf("YES\n%d\n", jie);
	else 
		puts("NO");
}

H. High Load Database

题意:有 n n 个东西重量总和不超过 1 e 6 1e6 ,有 q q 次询问容量为 x x 的背包按顺序装东西至少需要多少个背包能装完所有东西
解法:我们预处理一下所有 s i z e size 的背包一次性能装几个东西,每次询问我们暴力去模拟一下即可,复杂度为调和级数
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 5, N = 1e6;
int a[maxn], p[maxn], d[maxn], sum[maxn], mx, n;
int gao(int x) {
	if (x < mx)
		return -1;
	if (d[x])
		return d[x];
	int res = 0, i = 0;
	while (i < n) {
		res += x;
		res = min(res, N);
		i = p[res];
		res = sum[i];
		d[x]++;
	}
	return d[x];
}
int main()
{
	int q, x;
	scanf("%d", &n);
	for (int i = 1; i <= n; i++) {
		scanf("%d", &a[i]);
		mx = max(mx, a[i]);
		sum[i] = sum[i - 1] + a[i];
		for (int j = sum[i - 1]; j < sum[i]; j++)
			p[j] = i - 1;
	}
	for (int i = sum[n]; i <= N; i++)
		p[i] = n;
	scanf("%d", &q);
	while (q--) {
		scanf("%d", &x);
		if (gao(x) != -1)	
			printf("%d\n", gao(x));
		else 
			printf("Impossible\n");
	}
}

I. Ideal Pyramid

题意:给出 n n 个东西的二维坐标和高度,你要建立一个高度最小的四棱锥,包含住这 n n 个东西,要求四棱锥底面是个和 x x 轴平行的正方形,四棱锥的四个面和二维平面呈45度角,求四棱锥中间坐标和最小的高度(整型数,如果为小数,向上取整)
解法:太南了,我们写个简单版的题:在 x x 轴上有 n n 个东西有高度,你要在 x x 轴上建立一个高度最小的等腰直角三角形,斜边和 x x 轴重合,要求三角形能覆盖住这 n n 个东西。这个题你会写吧?那对于原题意,我们可以忽视 y y 坐标转化成 x x 轴上找小的等腰三角形包含住它们,忽视 x x 坐标转化成 y y 轴上找最小的等腰直角三角形包含住它们,结合起来就是答案

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1005;
struct node
{
    int x, y, h;
} a[maxn];
int main()
{
    int n, L1 = 2e9, L2 = 2e9, R1 = -2e9, R2 = -2e9, x, y;
    cin >> n;
    for (int i = 1; i <= n; i++)
        cin >> a[i].x >> a[i].y >> a[i].h;
    for (int i = 1; i <= n; i++)
    {
        L1 = min(L1, a[i].x - a[i].h);
        R1 = max(R1, a[i].x + a[i].h);
        L2 = min(L2, a[i].y - a[i].h);
        R2 = max(R2, a[i].y + a[i].h);
    }
    x = (L1 + R1) / 2;
    y = (L2 + R2) / 2;
    int h = max(x - L1, y - L2);
    int h2 = max(R1 - x, R2 - y);
    h = max(h, h2);
    printf("%d %d %d\n", (L1 + R1) / 2, (L2 + R2) / 2, h);
}

J. Just the Last Digit

题意:有一个有向图,满足如果 u > = v u>=v ,那么 u u 肯定不会有一条边走向 v v ,现在告诉你任意点 u u 到任意点 v v 的路径数模 10 10 等于 a [ u ] [ v ] a[u][v] ,让你恢复这个有向图 ( n < = 500 ) (n<=500)
解法:假设 u , v u,v 有一条单向边直接相连,那么 d [ u ] [ v ] = 1 d[u][v]=1, 我们从大到小枚举 u u ,然后从 u + 1 u+1 n n 枚举 v v ,然后枚举 u , v u,v 之间的点 k k ,设 s u m sum u u v v 的路径数,如果 d [ u ] [ k ] = 1 d[u][k]=1 ,那么 s u m + = a [ k ] [ v ] sum+=a[k][v] ,如果最后 s u m ! = a [ u ] [ v ] sum!=a[u][v] ,那么 u , v u,v 肯定有单向边
#include<bits/stdc++.h>
using namespace std;
const int maxn = 505;
char s[maxn][maxn];
int a[maxn][maxn];
int main()
{
	int n;
	scanf("%d", &n);
	for (int i = 1; i <= n; i++) {
		scanf("%s", s[i] + 1);
		for (int j = 1; j <= n; j++)
			s[i][j] -= '0';
	}
	for (int i = n - 1; i; i--)
		for (int j = i + 1; j <= n; j++) {
			int cat = 0;
			for (int k = i + 1; k < j; k++)
				cat = (cat + s[k][j] * a[i][k]) % 10;
			if (cat != s[i][j])
				a[i][j] = 1;
		}
	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= n; j++)
			printf("%d", a[i][j]);
		puts("");
	}
}
发布了302 篇原创文章 · 获赞 98 · 访问量 7万+

猜你喜欢

转载自blog.csdn.net/ccsu_cat/article/details/102978837