NOIP2023模拟3联测24-博弈树

2023-10-27 01:01
文章标签 模拟 24 博弈 联测 noip2023

本文主要是介绍NOIP2023模拟3联测24-博弈树,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

NOIP2023模拟3联测24-博弈树

文章目录

  • NOIP2023模拟3联测24-博弈树
    • 题目大意
    • 思路
    • code

题目大意

A l i c e Alice Alice B o b Bob Bob 又开始玩游戏了: 给定一颗 n n n 个节点的树, A l i c e Alice Alice B o b Bob Bob 随机选择一个节点作为起点放上棋子,由 Alice 先手。 轮到一方后可以将这颗棋子移动到树上任意一点,每次一方移动的距离必须比对 方上一次移动的距离还要大,开始时默认为 0 。 •当一方不能再次移动之后判负。 现在 Alice 和 Bob 已经找到了一棵节点编号为 1 ∼ n 1 ∼ n 1n 的树准备开始游戏,作为博弈 高手, A l i c e Alice Alice B o b Bob Bob 均会做出最优的选择,选择一个节点后,他们知道游戏必然有一种 必胜策略,现在他们想知道游戏的胜负,他们会询问你 q q q 次,每次他们会选择一个节点 询问,你只需要回答在最优策略下以这个为节点为起点的胜者是谁即可。

1 ≤ n , q ≤ 1 0 5 1\le n , q \le 10^5 1n,q105

思路

显然一棵树的最长路就是直径,所以当一个人走了与直径一样长的路径的时候必胜。

现在我们假设这棵树形成了一条链,显然只有在这条链的长度是奇数且起始点在中点时先手才必败,否则先手必胜。

我们开始不断删点,每次把当前树的直径的端点删掉,如果最后能够剩下一个点,那么先手必败,否则先手必胜。

我们发现这个最后剩下的那个点一定是原树上所有直径的交点,也是他们的中点。

所以只要只有在这个树的直径是奇数且起始点在直径的中点时先手才必败,否则先手必胜。

code

#include <bits/stdc++.h>
#define fu(x , y , z) for(int x = y ; x <= z ; x ++)
using namespace std;
const int N = 1e5 + 5;
int fa[N] , n , q , dep[N] , dis[N] , hd[N] , cnt , d , ans[N];
struct E {int to , nt;
} e[N << 1];
void add (int x , int y) { e[++cnt].to = y , e[cnt].nt = hd[x] , hd[x] = cnt; }
void dfs1 (int x) {int y;for (int i = hd[x] ; i ; i = e[i].nt) {y = e[i].to;if (y == fa[x]) continue;dep[y] = dep[x] + 1;fa[y] = x;dis[y] = dis[x] + 1;dfs1 (y);}
}
void dfs2 (int x , int lst) {int y;for (int i = hd[x] ; i ; i = e[i].nt) {y = e[i].to;if (y == lst) continue;dis[y] = dis[x] + 1;dfs2 (y , x);}
}
void solve (int x , int y) {int sum1 = 1 , sum2 = d;if (dep[x] < dep[y]) swap (x , y);while (dep[x] != dep[y]) {ans[sum1] = x;sum1 ++;x = fa[x];}if (sum1 == d) return;while (x != y) {ans[sum1] = x;ans[sum2] = y;sum1 ++;sum2 --;x = fa[x];y = fa[y];}if (d & 1) ans[sum1] = x;
}
int main () {freopen ("tree.in" , "r" , stdin);freopen ("tree.out" , "w" , stdout);int u , v;scanf ("%d%d" , &n , &q);if (n == 1) {while (q --) puts ("Bob"); return 0;}fu (i , 1 , n - 1) {scanf ("%d%d" , &u , &v);add (u , v) , add (v , u);}dfs1 (1);int max1 = 0 , pos1 , pos2;fu (i , 1 , n) {if (max1 < dis[i]) {max1 = dis[i];pos1 = i;}}memset (dis , 0 , sizeof (dis));dfs2 (pos1 , 0);max1 = 0;fu (i , 1 , n) {if (max1 < dis[i]) {max1 = dis[i];pos2 = i;}}d = max1 + 1;solve (pos1 , pos2);int mid = ans[d / 2 + 1];while (q --) {scanf ("%d" , &pos1);if (d & 1 && pos1 == mid) puts ("Bob");else puts ("Alice"); }
}

这篇关于NOIP2023模拟3联测24-博弈树的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/285863

相关文章

poj2505(典型博弈)

题意:n = 1,输入一个k,每一次n可以乘以[2,9]中的任何一个数字,两个玩家轮流操作,谁先使得n >= k就胜出 这道题目感觉还不错,自己做了好久都没做出来,然后看了解题才理解的。 解题思路:能进入必败态的状态时必胜态,只能到达胜态的状态为必败态,当n >= K是必败态,[ceil(k/9.0),k-1]是必胜态, [ceil(ceil(k/9.0)/2.0),ceil(k/9.

hdu3389(阶梯博弈变形)

题意:有n个盒子,编号1----n,每个盒子内有一些小球(可以为空),选择一个盒子A,将A中的若干个球移到B中,满足条件B  < A;(A+B)%2=1;(A+B)%3=0 这是阶梯博弈的变形。 先介绍下阶梯博弈: 在一个阶梯有若干层,每层上放着一些小球,两名选手轮流选择一层上的若干(不能为0)小球从上往下移动,最后一次移动的胜出(最终状态小球都在地面上) 如上图所示,小球数目依次为

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

usaco 1.2 Transformations(模拟)

我的做法就是一个一个情况枚举出来 注意计算公式: ( 变换后的矩阵记为C) 顺时针旋转90°:C[i] [j]=A[n-j-1] [i] (旋转180°和270° 可以多转几个九十度来推) 对称:C[i] [n-j-1]=A[i] [j] 代码有点长 。。。 /*ID: who jayLANG: C++TASK: transform*/#include<

hdu4431麻将模拟

给13张牌。问增加哪些牌可以胡牌。 胡牌有以下几种情况: 1、一个对子 + 4组 3个相同的牌或者顺子。 2、7个不同的对子。 3、13幺 贪心的思想: 对于某张牌>=3个,先减去3个相同,再组合顺子。 import java.io.BufferedInputStream;import java.io.BufferedReader;import java.io.IOExcepti

【每日一题】LeetCode 2181.合并零之间的节点(链表、模拟)

【每日一题】LeetCode 2181.合并零之间的节点(链表、模拟) 题目描述 给定一个链表,链表中的每个节点代表一个整数。链表中的整数由 0 分隔开,表示不同的区间。链表的开始和结束节点的值都为 0。任务是将每两个相邻的 0 之间的所有节点合并成一个节点,新节点的值为原区间内所有节点值的和。合并后,需要移除所有的 0,并返回修改后的链表头节点。 思路分析 初始化:创建一个虚拟头节点

每日一题|牛客竞赛|四舍五入|字符串+贪心+模拟

每日一题|四舍五入 四舍五入 心有猛虎,细嗅蔷薇。你好朋友,这里是锅巴的C\C++学习笔记,常言道,不积跬步无以至千里,希望有朝一日我们积累的滴水可以击穿顽石。 四舍五入 题目: 牛牛发明了一种新的四舍五入应用于整数,对个位四舍五入,规则如下 12345->12350 12399->12400 输入描述: 输入一个整数n(0<=n<=109 ) 输出描述: 输出一个整数

【算法专场】模拟(下)

目录 前言 38. 外观数列 算法分析 算法思路 算法代码 1419. 数青蛙 算法分析 算法思路 算法代码  2671. 频率跟踪器 算法分析 算法思路 算法代码 前言 在前面我们已经讲解了什么是模拟算法,这篇主要是讲解在leetcode上遇到的一些模拟题目~ 38. 外观数列 算法分析 这道题其实就是要将连续且相同的字符替换成字符重复的次数+

模拟实现vector中的常见接口

insert void insert(iterator pos, const T& x){if (_finish == _endofstorage){int n = pos - _start;size_t newcapacity = capacity() == 0 ? 2 : capacity() * 2;reserve(newcapacity);pos = _start + n;//防止迭代

PHP实现二叉树遍历(非递归方式,栈模拟实现)

二叉树定义是这样的:一棵非空的二叉树由根结点及左、右子树这三个基本部分组成,根据节点的访问位置不同有三种遍历方式: ① NLR:前序遍历(PreorderTraversal亦称(先序遍历)) ——访问结点的操作发生在遍历其左右子树之前。 ② LNR:中序遍历(InorderTraversal) ——访问结点的操作发生在遍历其左右子树之中(间)。 ③ LRN:后序遍历(PostorderT