首页 > 其他分享 >临时起意加塞 比赛总结

临时起意加塞 比赛总结

时间:2024-10-14 19:43:21浏览次数:1  
标签:总结 比赛 int root tree st rc 加塞 lc

临时起意加塞

T1 Hunte

T2 Defence

T3 Connect


从今天开始我要好好写比赛总结

赛时思路

今天由于没有特别睡醒,所以考试前一个小时状态不佳。

T1 看见 45pts 可做,决定写状压 dp。写了一个小时没写出来,然后改为去写状压 + 记搜,一下子就写出来了。

T2 上有策略的失误。T2 是线段树合并简单题。但是由于时间安排上的不合理在最后半个小时时才开始看 T2,而且在接下来的 20 分钟中,手玩样例错了两次(我也是服了我了。导致最后推出结论后暴力都没有打完。就很屎。

T3 的话,明智的,打了一个伪的最大生成树走人,拿 10pts。

总结

  1. 要解决打瞌睡的问题(很重要)。
  2. 要合理规划时间(很重要)。把每道题都大概想一点再去码代码。

题解

T1 Hunte

我们只考虑三个猎人 \(1\)、\(i\)、\(x\),然后我们不难发现 \(i\) 在 \(1\) 噶之前噶掉的概率就是 \(\frac{w_i}{w_1+w_i}\),也就是 \(x\) 在 \(i\) 和 \(1\) 中选择噶 \(i\) 的概率。那么对于每个除了 \(i\) 和 \(1\) 的猎人 \(x\) 都是如此。所以 \(\text{ans}=\sum_{i=2}^n \frac{w_i}{w_1+w_i}\)。

#include <bits/stdc++.h>
#define int long long

using namespace std;

const int MOD = 998244353;
const int N = 1e5 + 10;
int n, w[N];
int fpow(int a, int x) {
	a %= MOD;
	int ans = 1;
	while (x) {
		if (x & 1) ans = ans * a % MOD;
		a = a * a % MOD;
		x >>= 1;
	}
	return ans;
}
signed main() {
	freopen("hunter.in", "r", stdin);
	freopen("hunter.out", "w", stdout);
	scanf("%lld", &n);
	for (int i = 1; i <= n; i++) scanf("%lld", &w[i]);
	int ans = 1;
	for (int i = 2; i <= n; i++) {
		ans = (ans + w[i] * fpow(w[1] + w[i], MOD - 2) % MOD) % MOD;
	}
	printf("%lld\n", ans);
	
	return 0;
}

T2 Defence

T2 我们从子节点往父亲节点累加信息(在处理完子节点的信息后不要丢掉,通过修改操作转化为父亲节点的信息),这使我们不难想到线段树。又发现要考虑合并不同儿子的信息,并且要与父亲原有的信息合并,所以用线段树合并就行了。

#include <bits/stdc++.h>

using namespace std;

int read() {
	int x = 0; char ch = getchar();
	while (ch < '0' || ch > '9') ch = getchar();
	while (ch >= '0' && ch <= '9') {
		x = (x << 1) + (x << 3) + (ch ^ 48);
		ch = getchar();
	}
	return x;
}
const int N = 1e5 + 10;
int n, m, qq;
vector<int> G[N];
int ans[N];
int tot, root[N];
struct node {
	int lc, rc, s, l, r;
};
node tree[40 * N];
#define lc tree[p].lc
#define rc tree[p].rc
void pushup(int p, int l, int r) {
	if (!lc && !rc) tree[p].s = tree[p].l = tree[p].r = r - l + 1;
	int mid = l + r >> 1;
	if (!rc) {
		tree[p].s = max(tree[lc].s, tree[lc].r + r - mid);
		tree[p].l = tree[lc].l;
		tree[p].r = tree[lc].r + r - mid;
	} else if (!lc) {
		tree[p].s = max(tree[rc].s, tree[rc].l + mid - l + 1);
		tree[p].r = tree[rc].r;
		tree[p].l = tree[rc].l + mid - l + 1;
	} else {
		tree[p].s = max(tree[lc].r + tree[rc].l, max(tree[lc].s, tree[rc].s));
		tree[p].l = tree[lc].l;
		tree[p].r = tree[rc].r;
	}
}
void update(int &p, int l, int r, int x) {
	if (!p) p = ++tot;
	if (l == r) {
		tree[p].l = tree[p].r = tree[p].s = 0;
		return;
	}
	int mid = l + r >> 1;
	if (x <= mid) update(lc, l, mid, x);
	else update(rc, mid + 1, r, x);
	pushup(p, l, r);
}
#undef lc
#undef rc
int merge(int a, int b, int l, int r) {
	if (!a || !b) return a + b;
	if (l == r) {
		tree[a].l = tree[a].r = tree[a].s = 0;
		return a;
	}
	int mid = l + r >> 1;
	tree[a].lc = merge(tree[a].lc, tree[b].lc, l, mid);
	tree[a].rc = merge(tree[a].rc, tree[b].rc, mid + 1, r);
	pushup(a, l, r);
	return a;
}
void dfs(int x, int fa) {
	for (int y : G[x]) {
		if (y != fa) {
			dfs(y, x);
			root[x] = merge(root[x], root[y], 1, m);
		}
	}
	ans[x] = max(tree[root[x]].s, tree[root[x]].l + tree[root[x]].r);
	if (!root[x] || tree[root[x]].s == m) ans[x] = -1;
}
int main() {
	freopen("defence.in", "r", stdin);
	freopen("defence.out", "w", stdout);
	n = read(), m = read(), qq = read();
	for (int i = 1; i < n; i++) {
		int x = read(), y = read();
		G[x].push_back(y);
		G[y].push_back(x); 
	}
	for (int i = 1; i <= qq; i++) {
		int u = read(), p = read();
		update(root[u], 1, m, p);
	}
	dfs(1, 0);
	for (int i = 1; i <= n; i++) {
		printf("%d\n", ans[i]);
	}
	
	return 0;
}

T3 Connect

这是一道状压 dp。

设 \(f_{st,i}\) 表示现在选点的状态是 \(st\),路径的结尾是 \(i\) 的边权和的最大值。

然后有两种转移:

  1. 在路径的末尾加一个点。
  2. 加进去一坨点,且加进去的这么多点,只能与路径上的一个点连边。

至于那什么转移,第一种显然就是这条边的边权,第二种则是加进去的点集内的边权和加上与路径上一个点连边的边权和。

#include <bits/stdc++.h>
#define int long long

using namespace std;

const int INF = 0x3f3f3f3f3f3f3f3f;
const int N = 20, M = 32768 + 10;
int n, m, mp[N][N];
vector<int> G[N];
int rk[M];
int val[M], num[M][N];
int f[M][N];
void print(int x) {
	for (int i = 1; i <= n; i++) cout << ((x >> i - 1) & 1);
}
signed main() {
	freopen("connect.in", "r", stdin);
	freopen("connect.out", "w", stdout);
	scanf("%lld%lld", &n, &m);
	int sum = 0;
	for (int i = 1; i <= m; i++) {
		int x, y, w; 
		scanf("%lld%lld%lld", &x, &y, &w);
		G[x].push_back(y);
		G[y].push_back(x);
		mp[x][y] = mp[y][x] = w;
		sum += w;
	}
	for (int i = 1; i <= n; i++) rk[1 << i - 1] = i;
	for (int st = 0; st < (1 << n); st++) 
		for (int i = 1; i <= n; i++) 
			for (int j = i + 1; j <= n; j++) 
				if (((st >> i - 1) & 1) && ((st >> j - 1) & 1)) 
					val[st] += mp[i][j];
	for (int st = 0; st < (1 << n); st++) 
		for (int i = 1; i <= n; i++) 
			for (int j = 1; j <= n; j++) 
				if (!((st >> i - 1) & 1) && ((st >> j - 1) & 1)) 
					num[st][i] += mp[j][i];
	for (int st = 0; st < (1 << n); st++) 
		for (int i = 1; i <= n; i++) f[st][i] = -INF;
	f[1][1] = 0;
	for (int st = 0; st < (1 << n); st++) {
		for (int i = 1; i <= n; i++) {
			if (!((st >> i - 1) & 1)) continue;
			for (int j : G[i]) {
				if ((st >> j - 1) & 1) continue;
				f[st | (1 << j - 1)][j] = max(f[st | (1 << j - 1)][j], f[st][i] + mp[i][j]);
			}
			int s = (~st) & ((1 << n) - 1);
			for (int ss = s; ss; ss = (ss - 1) & s) {
				for (int sss = st; sss; sss -= (sss & -sss)) {
					int j = rk[sss & -sss];
					f[st | ss][i] = max(f[st | ss][i], f[st][i] + num[ss][j] + val[ss]);
				}
			}
		}
	}
	printf("%lld\n", sum - f[(1 << n) - 1][n]);
	
	return 0;
}

标签:总结,比赛,int,root,tree,st,rc,加塞,lc
From: https://www.cnblogs.com/zsk123qwq/p/18464880

相关文章

  • 程序员必看!从菜鸟到专家你要这么做,8年互联网老兵爆肝总结
    “互联网行业工作8年多,在国内Top互联网大厂B(ytedance)AT中的两家待过。喜欢研究计算机基础原理,有移动端全栈(包括Android&iOS&鸿蒙等)开发经验,对逆向和网络安全有一定经验。”不管是在校大学生,还是初入职场的菜鸟,抑或是在互联网行业打拼多年的老码农,相信这篇文章都能对你有所......
  • CTF 的基础知识 & 题型 & Trick总结
    references:12webphp语法基础references:1php脚本的基本格式:<?php//codinghere?>php代码同样以;结尾。php文件的后缀名大多是php,也有诸如php5php4phps之类,如果普通的后缀名被拦截不妨试试其他的。php变量用$来定义,大小写敏感,但是不用声明数据类型......
  • 2024/10/13 模拟赛总结
    人机体检,\(0+0+0+0=0\),打代码源去了#A.一般图最小匹配下次看到这种范围一定要想到dp啊,令\(dp_{i,j}\)为前\(i\)个元素选了\(j\)对点的最小代价由于边权是绝对值,可以对原数组排一遍序,选取的两个点就一定在排序后数组的相邻节点那么就可以得出式子:\(dp_{i,j}=\min\{dp_......
  • 从0-1入门Flink全网最全吐血总结
    Flink是Apache基金会旗下的一个开源大数据处理框架。目前,Flink已经成为各大公司大数据实时处理的发力重点,特别是国内以阿里为代表的一众互联网大厂都在全力投入,为Flink社区贡献了大量源码。如今Flink已被很多人认为是大数据实时处理的方向和未来,许多公司也都在招聘和......
  • python笔试--输入输出总结(四)
    1、递归函数递归函数是一种在函数内部调用自身的函数。递归是一种强大的编程方法,常用于解决那些可以分解为更小、更简单的问题的问题。递归函数通常遵循以下定义:基本案例(BaseCase):递归函数必须有一个或多个基本情况,这些情况是函数不再调用自身就能直接求解的条件。基本情况是......
  • 2025秋招NLP算法面试真题(二十二)-大模型参数高效微调技术总结与对比
    目录当前高效微调技术的简述BitFitPrefixTuningPromptTuningP-TuningP-Tuningv2AdapterTuningAdapterFusionAdapterDropLoRAAdaLoRA<......
  • 10.14考试总结
    0+100+0,这也没啥好说的了,反正就差的一批吧……\(T1\)\(Hunter\)简单数论题,但\(lyh\)从来没有在考试的时候\(A\)过数论题。考虑第一个人挂的时间\(=\)其他人比第一个人早挂的概率。对于第\(i\)个人,简化问题,只留第一个人和第\(i\)个人,答案就是\(\dfrac{w_i}{w_1+w_......
  • 人工智能是如何预测足球比赛?大小球亚盘数据分析推荐
    今天的文章主要包含了三部分内容:1,AI预测足球的过程。2,举例说明。3,影响AI预测准确率的原因。AI预测足球比赛的过程,其实并不复杂,主要就是下面几步,大家可以和自己平时预测比赛做个对照,看看我们和机器的区别在哪里:1,评估影响比赛结果的因素AI通过大模型的训练数据和知识库,运用机......
  • 10.7~10.13 总结
    联考的题解还是在这里。做题:ARC125F这就是\(\deg\)做背包。把所有\(\deg\)减一。现在限制是和为\(n-2\),每个数是自然数。有性质:选取和为\(y\)的数的个数连续。设\(L_y\)为最少选的数,\(R_y\)为最多。设有\(z\)个\(0\)。只需证明:\[R_x-L_x\le2z+1\]对于任意方案......
  • redis未授权访问及利用总结
    Redis未授权访问漏洞漏洞原理redis默认端口6379,在默认配置情况下密码为空,因此如果将redis暴露到公网,会导致任意用户在可以访问目标服务器的情况下未授权访问Redis以及读取Redis的数据,并且可以利用redis写入shell、写入公钥等危险操作漏洞复现安装redis下载安装包后进行解......