[赛记] 暑假集训CSP提高模拟26

news/2024/9/13 3:58:37/文章来源:https://www.cnblogs.com/PeppaEvenPig/p/18375714

这场rank4,应该是暑假以来打的最好的一场了。。。
其它时候就没进过前10。。。

博弈 30pts

赛时 $ O(n^2) $ 暴力30pts;

对于暴力,我们能发现一个性质就是只要有一类边权出现了奇数次,那么先手必胜,所以我们枚举每一个点对,开个数组统计一下即可;

不要忘了离散化;

对于正解,用到了一个东西:$ xor-hashing $;

其实对于这种判断奇偶的问题,我们很容易想到 $ xor $,因为当有偶数个相同的数出现时, 他们 $ xor $ 起来的值是为 $ 0 $ 的,所以我们只需判断树上任意两点间的路径异或和是否为 $ 0 $ 即可;

那么我们做一下树上差分,记一下从根(指定一个)到每个点的异或和,然后找一下相同的减去其贡献即可(这是根据异或的性质:两个相同的数异或值为 $ 0 $, $ 0 \operatorname{xor} x = x $);

但是我们发现这样并不能保证正确性,比如 $ 1 \operatorname{xor} 2 \operatorname{xor} 3 = 0 $,但这种情况是先手必胜,判断出来是后手必胜,出现了冲突;

发现这其实很像 $ hash $,所以我们可以给每类边权随一个在 $ unsigned \ long \ long $ 范围内的值,这样正确判断的概率就很大了;

随权值的操作可以用mt19937_64 来实现;

其实思路过程可能应该是点分治,不行再到树上差分,再到异或,再到 $ xor-hashing $(当然赛时可能到不了);

这应该就是 $ xor-hashing $ 的基本应用了;

点击查看代码
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <map>
#include <ctime>
#include <cstdlib>
#include <random>
using namespace std;
int t;
int n;
int x[5000005], y[500005], w[500005], b[500005];
unsigned long long p[500005];
unsigned long long ha[500005];
map<unsigned long long, int> sum;
map<unsigned long long, bool> vis;
struct sss{int t, ne;unsigned long long w;
}e[1000005];
int h[1000005], cnt;
void add(int u, int v, unsigned long long ww) {e[++cnt].t = v;e[cnt].ne = h[u];h[u] = cnt;e[cnt].w = ww;
}
void dfs(int x, int fa) {sum[ha[x]]++;for (int i = h[x]; i; i = e[i].ne) {int u = e[i].t;if (u == fa) continue;ha[u] = ha[x] ^ e[i].w;dfs(u, x);}
}
long long ans;
int main() {ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);mt19937_64 ran(time(0));cin >> t;for (int i = 1; i <= 500000; i++) {p[i] = ran();}while(t--) {cin >> n;cnt = 0;ans = 0;memset(h, 0, sizeof(h));memset(ha, 0, sizeof(ha));sum.clear();vis.clear();for (int i = 1; i <= n - 1; i++) {cin >> x[i] >> y[i] >> w[i];b[i] = w[i];}sort(b + 1, b + 1 + n - 1);int len = unique(b + 1, b + 1 + n - 1) - b - 1;for (int i = 1; i <= n - 1; i++) {add(x[i], y[i], p[lower_bound(b + 1, b + 1 + len, w[i]) - b]);add(y[i], x[i], p[lower_bound(b + 1, b + 1 + len, w[i]) - b]);}dfs(1, 0);for (int i = 1; i <= n; i++) {if (sum[ha[i]] && !vis[ha[i]]) {vis[ha[i]] = true;ans += 1ll * (sum[ha[i]] * (sum[ha[i]] - 1) / 2);}}cout << 1ll * n * (n - 1) / 2 - ans << '\n';}return 0;
}

大陆 100pts

赛时切了,还是首A。。。

其实这个题就是模拟一下即可;

考虑从下往上删子树,因为各个子树互不影响;

那么当我们回溯时,判断一下当前子树是否符合要求,若符合,则直接删掉;

这样我们会发现一个问题,就是可能会剩下一些点,这些点都和根组成一个连通块,且大小小于b;

那么我们想要把它们并入一个其它的,已划分出的连通块去,那么这个连通块的大小要小于等于2倍的b;

所以我们把划分条件改一下,当一棵子树的大小大于等于b且小于等于2倍的b时,就把它划出去;

那这样我们还会出现另一个问题,就是当一棵子树的子树很多时,可能出现这棵子树的大小大于2倍的b,但它的任意一棵子树的大小都小于b的情况,对于这种情况,我们直接单独考虑,每b个划分一次,不足b个的并入先前的连通块中,这样就满足要求了;

这样的话,我们划分出的最后一个连通块可能会大于2倍的b,小于3倍的b,这样就不能使根节点连的块并入此块,所以我们将这颗子树的根并入第一个连通块,因为第一个连通块大小是小于等于2倍的b的,这样就可以使根节点连的块并入第一个块了;

这题还是可以练练搜索能力的;

点击查看代码
#include <iostream>
#include <cstdio>
using namespace std;
int n, b;
struct sss{int t, ne;
}e[50005];
int h[50005], cnt;
void add(int u, int v) {e[++cnt].t = v;e[cnt].ne = h[u];h[u] = cnt;
}
int siz[50005];
int c[50005], tot, cap[50005], sum[50005], fa[50005];
int aa;
void dfs(int x, int f) {siz[x] = 1;fa[x] = f;for (int i = h[x]; i; i = e[i].ne) {int u = e[i].t;if (u == f) continue;dfs(u, x);siz[x] += siz[u];}
}
void cfs(int x) {c[x] = tot;sum[tot]++;for (int i = h[x]; i; i = e[i].ne) {int u = e[i].t;if (u == fa[x] || c[u]) continue;cfs(u);}
}
void efs(int x) {int su = 0;int ssu = 0;tot++;cap[tot] = x;sum[tot]++;c[x] = tot; //并入第一个块;for (int i = h[x]; i; i = e[i].ne) {int u = e[i].t;if (u == fa[x]) continue;if (c[u]) continue;su += siz[u];ssu += siz[u];cfs(u);if (su >= b) {tot++;if (siz[x] - ssu - 1 < b) {tot--;}cap[tot] = x;su = 0;}}
}
void afs(int x) {for (int i = h[x]; i; i = e[i].ne) {int u = e[i].t;if (u == fa[x]) continue;afs(u);}if (siz[x] >= b && siz[x] <= 2 * b) {tot++;cap[tot] = x;cfs(x);for (int i = fa[x]; i; i = fa[i]) {siz[i] -= siz[x];}} else if (siz[x] > 2 * b) {efs(x);for (int i = fa[x]; i; i = fa[i]) {siz[i] -= siz[x];}}
}
void ddfs(int x, int fa) {if (c[x]) {aa = c[x];return;}for (int i = h[x]; i; i = e[i].ne) {int u = e[i].t;if (u == fa) continue;ddfs(u, x);}
}
int main() {ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);cin >> n >> b;int x, y;for (int i = 1; i <= n - 1; i++) {cin >> x >> y;add(x, y);add(y, x);}dfs(1, 0);if (siz[1] >= b && siz[1] <= 3 * b) {cout << 1 << '\n';for (int i = 1; i <= n; i++) {cout << 1 << ' ';}cout << '\n';cout << 1;return 0;}afs(1);if (!c[1]) {aa = 0;ddfs(1, 0);for (int i = 1; i <= n; i++) {if (!c[i]) c[i] = aa;}}cout << tot << '\n';for (int i = 1; i <= n; i++) {cout << c[i] << ' ';}cout << '\n';for (int i = 1; i <= tot; i++) {cout << cap[i] << ' ';}return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/786020.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

conv1D,conv2D,和conv3D

torch.nn.Conv1d(in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True, padding_mode=zeros, device=None, dtype=None)

wqs 二分学习笔记

蒟蒻的第一篇学习笔记qwq wqs二分用于解决此类问题 n个物品,从中选恰好m个,最大化收益。而且你发现,如果没有选m个的限制,这道题是非常好做的。 使用前提 1、恰好选k个,至多至少不行 2、答案满足凸性 什么是凸性? 设选i个物品时的收益为fi 如果把它画成函数,那么它长这样…

使用 reloadNuxtApp 强制刷新 Nuxt 应用

title: 使用 reloadNuxtApp 强制刷新 Nuxt 应用 date: 2024/8/22 updated: 2024/8/22 author: cmdragon excerpt: reloadNuxtApp 是一个强大的工具,用于在 Nuxt 3 应用中强制刷新页面。通过不同的选项,你可以控制刷新行为、指定路径、保存状态等。 categories:前端开发tags:…

[Ynoi2016] 掉进兔子洞

题目链接 : [Ynoi2016] 掉进兔子洞 好不容易争取来的三天没有模拟赛,不打Ynoi打什么。 先从莫队+bitset的板板开始,第一个自己打出来的Ynoi捏。 一个套路,就是将每个数离散化后的值变成小于等于它的数的个数,然后就可以用bitset记录出现次数了。 具体的操作就是,假如一个数…

还有程序员不会玩黑神话悟空?是我太菜了

我承认是我天真了,本来计划周二晚上公开直播新项目教学的,但是发现黑神话悟空这游戏的热度火的有点过头了啊!所以临时决定把新项目直播移到周四晚上 8 点。直播打游戏!大家好,我是程序员鱼皮。我承认是我天真了,本来计划周二晚上公开直播新项目教学的,但是发现黑神话悟空…

Git GUI与命令全能操作,转载

Git 命令基本操作 Git GUI全能基本操作 看 https://blog.csdn.net/chehec2010/article/details/89950964gui 目录 1、版本库初始化 gitpractise文件夹就变成了Git可以管理的仓库,目录下多了一个.git文件夹,此目录是Git用于管理版本库的,不要擅自改动里面的文件,这样会破坏…

spring boot简单运用ollama大模型(windows版本)

1、下载模型(windows为例)打开官方网站https://ollama.com/download/windows。打开exe文件,打开命令行工具,直接运行ollama run 要下载的模型(右上角的models能找到你想要的,例子以llama3.1展示,spring ai暂时非全支持,支持模型步骤2列出)运行完后直接是这样显示至此,…

048、Vue3+TypeScript基础,页面通讯之子页面调用父页面的事件

01、main.js代码如下:// 引入createApp用于创建Vue实例 import {createApp} from vue // 引入App.vue根组件 import App from ./App.vueconst app = createApp(App);// App.vue的根元素id为app app.mount(#app)02、App.vue代码如下:<template><div class="app&…

YOLOv5实战记录 Gradio搭建Web GUI

转自:https://blog.csdn.net/EmileJiao/article/details/137448176最终的:import torch import gradio as grmodel=torch.hub.load("./","custom",path="runs/train/exp2/weights/best.pt",source="local")title="基于Gradio的YO…

火山引擎VeDI实验平台助推企业量化决策能力升级

DataTester技术团队基于并行化的Leiden算法,快速处理亿级用户的复杂社交网络,完成基于社交圈的聚类分流。 更多技术交流、求职机会,欢迎关注字节跳动数据平台微信公众号,回复【1】进入官方交流群 量化决策,正成为企业在数智化浪潮中掌握方向的必备之舵。通过“拍脑袋”式的…

基础组件:文本及样式

一、Text Text 用于显示简单样式文本,它包含一些控制文本显示样式的一些属性,一个简单的例子如下: Text("Hello world",textAlign: TextAlign.left, );Text("Hello world! Im Jack. "*4,maxLines: 1,overflow: TextOverflow.ellipsis, );Text("Hel…

设计模式[5]-代理模式

代码:https://gitee.com/Aes_yt/design-pattern代理模式 代理模式需要给某对象提供一个代理来访问该对象。是客户端和目标对象之间的一个媒介。 代理模式主要包括三种角色抽象主题:接口或抽象类,有着业务方法,可以让真实主题和代理对象来实现。 真实主题:实现了抽象主题的…