专栏文章

20250817 LiveDream 模拟赛总结

个人记录参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@mio9it16
此快照首次捕获于
2025/12/02 15:34
3 个月前
此快照最后确认于
2025/12/02 15:34
3 个月前
查看原文

总结

炸大分

T1

签到,每次把 A 丢到后面,如果丢不了了直接清空。
CPP
#include <bits/stdc++.h>
#define int long long

using namespace std;

const int kMaxN = 5e5 + 5;

int cnt, n, ans;
string s;

signed main() {
	cin >> s, n = s.size(), s = " " + s;
	for (int i = 1; i <= n; i++) {
		if (s[i] == 'A') cnt++;
		else if (i + 1 <= n && s[i] == 'B' && s[i + 1] == 'C') {
			ans += cnt, i++;
		} else cnt = 0;
	}
	cout << ans << '\n';
	return 0;
} 

T2

考虑到在一个连通块里如果边数大于等于点数,那么一定可以供应,并不用关心怎么供应的。考虑贪心,从大往下连,使用并查集维护边和点数。
CPP
#include <bits/stdc++.h>
#define i64 long long

using namespace std;

const i64 kMaxN = 2e5 + 5;

struct N{
	i64 u, v, w;
} a[kMaxN];

i64 Fa[kMaxN], edge[kMaxN], note[kMaxN], n, m, ans;

i64 F(i64 x) {
	return Fa[x] == x ? x : Fa[x] = F(Fa[x]);
}

bool cmp(N A, N B) {
	return A.w > B.w;
}

signed main() {
	i64 T;
	for (cin >> T; T; T--) {
		cin >> n >> m, ans = 0;
		for (i64 i = 1; i <= n; i++) {
			Fa[i] = i, edge[i] = 0, note[i] = 1;
		}
		for (i64 i = 1; i <= m; i++) {
			cin >> a[i].u >> a[i].v >> a[i].w;
		}
		sort(a + 1, a + m + 1, cmp);
		for (i64 i = 1; i <= m; i++) {
			i64 x = F(a[i].u), y = F(a[i].v);
			if (x == y) {
				if (edge[x] < note[x]) edge[x]++, ans += a[i].w;
			} else {
				if (edge[x] < note[x] || edge[y] < note[y]) {
					Fa[x] = y;
					edge[y] += edge[x] + 1;
					note[y] += note[x];
					ans += a[i].w; 
				}
			}
		} 
		cout << ans << '\n';
	}
	return 0;
}

T3

树形 DP 我是真不会啊。
cnt2icnt2_i 表示 22ii 的贡献,cnt5icnt5_i 表示 55ii 的贡献。对于 xx 分开计算贡献,在子树内,LCA 必定为 xx,答案为 cntx×szxcnt_x \times sz_x;在 x 的子树外,必定在他的祖先上,这部分的答案直接从父亲继承再加上以父亲为答案的贡献,答案为 cntfa(szfaszx)cnt_{fa} * (sz_{fa} - sz_x)。最终答案讲 2255 取最小值。
CPP
#include <bits/stdc++.h>
#define i64 long long

using namespace std;

const int kMaxN = 2e5 + 5;

int c2[kMaxN], c5[kMaxN], sz[kMaxN], f2[kMaxN], f5[kMaxN], ans[kMaxN], n, q;
vector<int> G[kMaxN];

int C2(int x, int ret = 0) {
	for (; x % 2 == 0; x /= 2, ret++);
	return ret;
}

int C5(int x, int ret = 0) {
	for (; x % 5 == 0; x /= 5, ret++);
	return ret;
}

void dfs(int x, int fa) {
	sz[x] = 1;
	for (auto v : G[x]) if (v != fa) {
		dfs(v, x), sz[x] += sz[v];
	}
}

void dfs1(int x, int fa) {
	f2[x] = f2[fa] + c2[fa] * (sz[fa] - sz[x]);
	f5[x] = f5[fa] + c5[fa] * (sz[fa] - sz[x]);
	ans[x] = min(f2[x] + c2[x] * sz[x], f5[x] + c5[x] * sz[x]);
	for (auto v : G[x]) if (v != fa) {
		dfs1(v, x);
	}
}

signed main() {
	cin >> n >> q;
	for (int i = 1; i <= n; i++) c2[i] = C2(i), c5[i] = C5(i);
	for (int i = 1; i < n; i++) {
		int x, y; cin >> x >> y;
		G[x].push_back(y), G[y].push_back(x);
	}
	dfs(1, 0), dfs1(1, 0);
	for (int i = 1; i <= q; i++) {
		int x; cin >> x;
		cout << ans[x] << '\n';
	} 
	return 0;
}

T4

数据很小,可以状压。
首先考虑一批一批的选数字,从 00 开始选。
考虑一个链的情况,发现选的是独立集(不能相邻)。放到树上,即是邻居不能重复选,gig_i 表示状压 ii 的邻居, wiw_i 表示在状压的 ii 状态下的所有邻居。转移的时候枚举子集,判断并累加答案。
CPP
#include <bits/stdc++.h>
#define i64 long long

using namespace std;

const int kMaxN = 20;

int w[1 << kMaxN], f[1 << kMaxN], g[1 << kMaxN], n, m;

signed main() {
    cin >> n >> m;
    for (int i = 1; i <= m; i++) {
        int u, v; cin >> u >> v, u--, v--;
        g[u] |= 1 << v, g[v] |= 1 << u;
    }
    for (int i = 0; i < (1 << n); i++) {
        for (int j = 0; j < n; j++) {
            if (i & (1 << j)) w[i] |= g[j];
        }   
    }
    f[0] = 1;
    for (int i = 1; i < (1 << n); i++) {
        for (int j = i; j; j = i & (j - 1)) {
            if ((w[j] & j) == 0 && ((w[j] & (i ^ j)) == (i ^ j)))  {
                f[i] += f[i ^ j];
            }
        }
    }
    cout << f[(1 << n) - 1] << '\n';
    return 0;
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...