2020杭电多校第二场题解

Posted st1vdy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2020杭电多校第二场题解相关的知识,希望对你有一定的参考价值。

2020 Multi-University Training Contest 2

施工中。。。

1001 Total Eclipse

并查集。由于每次选择最大的连通块,所以连通块每次选择最小的点,删除后选择新的连通块组继续操作。

对于每个连通块,用并查集反向处理连通块即可。

  • 将当前最大的点加入图,并删除该点,连通块数加一
  • 遍历该点的边,每与一个不同的集合合并,连通块数减一
  • 每次贡献为连通块数 * (该点的权值 - 下一个点的权值)
#include <bits/stdc++.h>
using namespace std;

typedef long long LL;
typedef pair<int, int> pii;
const int maxn = 1e5 + 5;
int b[maxn], f[maxn];
bool vis[maxn];
vector<int> E[maxn];
vector<int> V[maxn];

int main() {
	int t;
	scanf("%d", &t);

	function<int(int)> find;
	find = [&](int x)->int {
		while (x != f[x])
			x = f[x] = f[f[x]];
		return x;
	};

	while (t--) {
		int n, m;
		scanf("%d%d", &n, &m);
		for (int i = 1; i <= n; i++) {
			scanf("%d", &b[i]);
			E[i].resize(0);
			V[i].resize(0);
			vis[i] = false;
			f[i] = 0;
		}
		int u, v;
		for (int i = 1; i <= m; i++) {
			scanf("%d%d", &u, &v);
			E[u].push_back(v);
			E[v].push_back(u);
		}

		int k = 0;
		function<void(int)> dfs;
		dfs = [&](int now) {
			vis[now] = true;
			V[k].push_back(now);
			for (auto it : E[now]) {
				if (vis[it]) continue;
				dfs(it);
			}
		};

		LL ans = 0;
		for (int i = 1; i <= n; i++) {
			if (vis[i]) continue;
			k++;
			dfs(i);
			V[k].push_back(0);
			sort(V[k].begin(), V[k].end(), [&](const int o1, const int o2) {
				return b[o1] > b[o2];
			});
			LL cnt = 0;
			for (int j = 0; j < (int)V[k].size();) {
				if (!V[k][j]) break;
				int p = j;
				while (++j < (int)V[k].size() && V[k][j] == V[k][j - 1])
					;
				for (int g = p; g < j; g++) {
					int now = V[k][g];
					f[now] = now;
					cnt++;
					for (auto it : E[now]) {
						if (!f[it])
							continue;
						if (find(now) != find(it))
							f[find(now)] = find(it),
							cnt--;
					}
				}
				ans = ans + cnt * (b[V[k][p]] - b[V[k][j]]);
			}
		}
		printf("%lld
", ans);
	}
	return 0;
}

1006 The Oculus

预处理出 (fib[i]\%mod) 的值,且令 (fib[i]\%mod) 的值不同

已知斐波那契数为 ([1,2e6+5]),所以可以预处理 (mod) 是否每个斐波数的模数不同

根据斐波那契数编码,将 (a、b、c) 求余 (mod) 的值计算出来出来

由于 (fib[i]\%mod) 的值各不相同,则存在唯一值使得 ((c+fib[i])\%mod=a*b\%mod)

#include <bits/stdc++.h>
using namespace std;

typedef long long LL;
const LL mod = 3799912185593857;
const int maxn = 2e6 + 5;
LL fib[maxn];
int a[maxn];

int main() {
	fib[0] = fib[1] = 1;
	for (int i = 2; i < maxn; i++) {
		fib[i] = fib[i - 1] + fib[i - 2];
		if (fib[i] >= mod) fib[i] -= mod;
	}

	int t;
	scanf("%d", &t);
	while (t--) {
		int n, x, p, q;
		scanf("%d", &p);
		LL a = 0;
		for (int i = 1; i <= p; i++) {
			scanf("%d", &x);
			if (x) {
				a = a + fib[i];
				if (a >= mod) a -= mod;
			}
		}
		scanf("%d", &q);
		LL b = 0;
		for (int i = 1; i <= q; i++) {
			scanf("%d", &x);
			if (x) {
				b = b + fib[i];
				if (b >= mod) b -= mod;
			}
		}
		scanf("%d", &n);
		LL c = 0;
		for (int i = 1; i <= n; i++) {
			scanf("%d", &x);
			if (x) {
				c = c + fib[i];
				if (c >= mod) c -= mod;
			}
		}
		LL ans = __int128(a) * b % mod;
		for (int i = 1; i <= max(n, p + q + 1); i++) {
			LL temp = c + fib[i];
			if (temp >= mod) temp -= mod;
			if (temp == ans) {
				printf("%d
", i);
				break;
			}
		}
	}
	return 0;
}

1009 It‘s All Squares

本题实质是一个算复杂度的问题 。显然最大图形为 (400*400),有 (4e6/4/400=2500) 个图形, (400*400*2500=4e8) 换言之,矩形每个可以用 (O(n*m)) 复杂度完成。

对于每个多边形处理出 (x_{min},x_{max},y_{min},y_{max}) ,然后每行处理出所有竖的边界,在两个相邻边界内的就是在多边形内

(对边界排序可以用基数,但是 (sort) 也可以 (qwq))。

#include <bits/stdc++.h>
using namespace std;

const int maxn = 405;
const int inf = 0X3f3f3f3f;
int w[maxn][maxn];

char s[maxn * maxn];
int line[maxn][maxn], top[maxn];

bool a[maxn * maxn];
int cnt[maxn * maxn];

int main() {
    int t;
    scanf("%d", &t);
    while (t--) {
        int n, m, q;
        scanf("%d%d%d", &n, &m, &q);
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= m; j++)
                scanf("%d", &w[i][j]);

        for (int l = 1; l <= q; l++) {
            int x, y;
            scanf("%d%d", &x, &y);
            scanf("%s", s + 1);
            int len = strlen(s + 1);
            int min_x = x, max_x = x, min_y = y, max_y = y;
            for (int i = 1; i <= len; i++) {
                if (s[i] == ‘L‘)
                    x--;
                else if (s[i] == ‘R‘)
                    x++;
                else if (s[i] == ‘D‘)
                    y--;
                else
                    y++;
                min_x = min(min_x, x);
                max_x = max(max_x, x);
                min_y = min(min_y, y);
                max_y = max(max_y, y);
                if (s[i] == ‘L‘)
                    line[x + 1][++top[x + 1]] = y;
                else if (s[i] == ‘R‘)
                    line[x][++top[x]] = y;
            }

            int g = 0;
            for (int i = min_x + 1; i <= max_x; i++) {
                if (!top[i])
                    continue;
                sort(line[i] + 1, line[i] + top[i] + 1);

                for (int j = 1; j <= top[i]; j += 2) {
                    for (int k = line[i][j] + 1; k <= line[i][j + 1]; k++) {

                        if (!a[w[i][k]]) {
                            a[w[i][k]] = true;
                            cnt[++g] = w[i][k];
                        }
                    }
                }
                top[i] = 0;
            }
            for (int i = 1; i <= g; i++)
                a[cnt[i]] = false;
            printf("%d
", g);
        }
    }
    return 0;
}

1010 Lead of Wisdom

(n) 个装备 (k)((n,kleq 50)) ,所以装备方案最多为 (3^{16}*2),所以直接爆搜+剪枝。

剪枝可以剪下界,(事实上,不剪也可以过)用每种装备最大的 (a,b,c,d) 代表每种装备的最优取值,用后缀表示最优装备的后缀,在搜索过程中若采用最优后缀仍无法超过已知最优解,则可以剪枝。

#include<bits/stdc++.h>
#define ll long long
#define maxn 100010
using namespace std;
ll ma[100][5];
ll sum[100][5];
ll val[100][5];
ll ans = 0;
int n, k;
vector<int>b[100];
void sol(int x, ll a1, ll a2, ll a3, ll a4) {
	ans = max(ans, (a1 + 100) * (a2 + 100) * (a3 + 100) * (a4 + 100));
	if (x == k) return;
	if (ans >= (a1 + sum[x][0] + 100) * (a2 + sum[x][1] + 100) * (a3 + sum[x][2] + 100) * (a4 + sum[x][3] + 100)) return;
	for (int i = 0; i < b[x + 1].size(); i++) {
		int j = b[x + 1][i];
		sol(x + 1, a1 + val[j][0], a2 + val[j][1], a3 + val[j][2], a4 + val[j][3]);
	}
	sol(x + 1, a1, a2, a3, a4);
}

int main() {
	int t;
	scanf("%d", &t);
	while (t--) {
		scanf("%d%d", &n, &k);
		memset(sum, 0, sizeof(sum));
		memset(val, 0, sizeof(val));
		memset(ma, 0, sizeof(ma));
		for (int i = 0; i <= k; i++) b[i].clear();
		for (int i = 0; i < n; i++) {
			int x;
			scanf("%d", &x);
			for (int j = 0; j < 4; j++) {
				scanf("%lld", &val[i][j]);
				ma[x][j] = max(ma[x][j], val[i][j]);
			}
			b[x].push_back(i);
		}
		for (int i = k - 1; i >= 0; i--)
			for (int j = 0; j < 4; j++) 
				sum[i][j] = sum[i + 1][j] + ma[i + 1][j];
		ans = 0;
		sol(0, 0, 0, 0, 0);
		printf("%lld
", ans);
	}
	return 0;
}

1012 String Distance

由于 (m) 串只有 (20) ,首先预处理 (n) 串每个字符后面第 (i) 个字符的位置。

对于每次询问搜索 (LCS) ,用 (dp[i][j]) 表示 (LCS)(i) 位是 (m) 串第 (j) 位时,对应字符在 (n) 串的位置,若在([left,right]) 范围内,即合理。

[egin{gather*}dp[i+1][j]=min(w[dp[i][j-k]][p[k]-‘a‘])(1leq k <j)end{gather*} ]

#include <bits/stdc++.h>
using namespace std;

const int maxn = 1e5 + 5;
const int inf = 0X3f3f3f3f;
char s[maxn], p[30];
int w[maxn][26];
int dp[21][21];

int main() {
	int t;
	scanf("%d", &t);
	while (t--) {
		scanf("%s%s", s + 1, p + 1);
		int n = strlen(s + 1);
		int m = strlen(p + 1);
		for (int i = 0; i < 26; i++)
			w[n][i] = inf;
		for (int i = n - 1; i >= 0; i--) {
			for (int j = 0; j < 26; j++)
				w[i][j] = w[i + 1][j];
			w[i][s[i + 1] - ‘a‘] = i + 1;
		}
		int q;
		scanf("%d", &q);
		while (q--) {
			int left, right;
			scanf("%d%d", &left, &right);
			int ans = 0;
			memset(dp, 0X3f, sizeof(dp));
			for (int i = 1; i <= m; i++)
				dp[1][i] = w[left - 1][p[i] - ‘a‘];
			for (int i = 1; i <= m; i++) {
				for (int j = 1; j <= m; j++) {
					if (dp[i][j] <= right) {
						ans = max(ans, i);
						for (int k = j + 1; k <= m; k++)
							dp[i + 1][k] = min(dp[i + 1][k], w[dp[i][j]][p[k] - ‘a‘]);
					}
				}
			}
			ans = right - left + 1 - ans + m - ans;
			printf("%d
", ans);

		}
	}
	return 0;
}

以上是关于2020杭电多校第二场题解的主要内容,如果未能解决你的问题,请参考以下文章

2020杭电多校第二场 1006.The Oculus

[2020杭电多校第二场]1005 New Equipments(费用流)

2018杭电多校第二场1003(DFS,欧拉回路)

2022杭电多校第二场 A.Static Query on Tree(树剖)

2022杭电多校第二场 A.Static Query on Tree(树剖)

2022杭电多校第二场 A.Static Query on Tree(树剖)