码迷,mamicode.com
首页 > 其他好文 > 详细

2020杭电多校第二场题解

时间:2020-07-23 23:11:17      阅读:218      评论:0      收藏:0      [点我收藏+]

标签:mes   存在   long   typedef   line   pair   fine   剪枝   排序   

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\n", 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\n", 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\n", g);
        }
    }
    return 0;
}

1010 Lead of Wisdom

\(n\) 个装备 \(k\)\((n,k\leq 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\n", ans);
	}
	return 0;
}

1012 String Distance

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

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

\[\begin{gather*}dp[i+1][j]=min(w[dp[i][j-k]][p[k]-‘a‘])(1\leq 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\n", ans);

		}
	}
	return 0;
}

2020杭电多校第二场题解

标签:mes   存在   long   typedef   line   pair   fine   剪枝   排序   

原文地址:https://www.cnblogs.com/st1vdy/p/13368701.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!