Solution -「多校联训」博弈
\(\mathcal{Description}\)
Link.
A B 两人在树上博弈,初始时有一枚棋子在结点 \(1\)。由 A 先操作,两人轮流移动沿树上路径棋子,且满足本次移动的树上距离严格大于上次的,无法移动者负。先给定一棵含 \(n\) 个结点的树,求包含结点 \(1\) 且使得 B 必胜的联通块数量。
\(n\le2\times10^5\)。
\(\mathcal{Solution}\)
结论对了正解写了细节萎了暴力分都没了 qwq……
结论:联通块满足条件,当且仅当其中最深的叶子们不同时属于结点 \(1\) 的某棵子树。当然也能说作,结点 \(1\) 是联通块直径的中点。
证:略。
“不同时属于”不太优美,考虑用所有方案减去非法方案。对于结点 \(1\) 的每棵子树,分别做长剖求出 \(f(v,d)\) 表示以 \(v\) 为根,最深叶子深度恰为 \(d\) 的联通块个数。随后钦定某棵子树取 \(d\),其余子树取严格小于 \(d\) 的方案,即能求出答案。
复杂度 \(\mathcal O(n)\)(其实我写得比较难看,会有一个求逆元的 \(\log\) awa……)
\(\mathcal{Code}\)
/* Clearink */
#include <list>
#include <cstdio>
#define rep( i, l, r ) for ( int i = l, rep##i = r; i <= rep##i; ++i )
#define per( i, r, l ) for ( int i = r, per##i = l; i >= per##i; --i )
typedef std::pair<int, int> PII;
#define fi first
#define se second
inline int rint() {
int x = 0, s = getchar();
for ( ; s < '0' || '9' < s; s = getchar() );
for ( ; '0' <= s && s <= '9'; s = getchar() ) x = x * 10 + ( s ^ '0' );
return x;
}
const int MAXN = 2e5, MOD = 998244353;
int n, ecnt, head[MAXN + 5];
int mxd[MAXN + 5], son[MAXN + 5];
PII *top, pool[MAXN * 5 + 10], *f[MAXN + 5];
// second 是乘法标记,转移过程中涉及到对长链的后缀乘法,需要打标记。
// 其实呢,由于出题人*****,更新时直接遍历长链也能过√
struct Edge { int to, nxt; } graph[MAXN * 2];
std::list<int> rt;
inline int sub( int a, const int b ) { return ( a -= b ) < 0 ? a + MOD : a; }
inline int add( int a, const int b ) { return ( a += b ) < MOD ? a : a - MOD; }
inline int mul( const long long a, const int b ) { return int( a * b % MOD ); }
inline int mpow( int a, int b ) {
int ret = 1;
for ( ; b; a = mul( a, a ), b >>= 1 ) ret = mul( ret, b & 1 ? a : 1 );
return ret;
}
inline void link( const int u, const int v ) {
graph[++ecnt] = { v, head[u] }, head[u] = ecnt;
graph[++ecnt] = { u, head[v] }, head[v] = ecnt;
}
inline PII* alloc( const int len ) {
PII* ret = top; top += len + 3;
return ret;
}
inline int init( const int u, const int fa ) {
int ret = 1;
mxd[u] = son[u] = 0;
for ( int i = head[u], v; i; i = graph[i].nxt ) {
if ( ( v = graph[i].to ) != fa ) {
ret = mul( ret, add( init( v, u ), 1 ) );
if ( mxd[u] < mxd[v] + 1 ) mxd[u] = mxd[son[u] = v] + 1;
}
}
// printf( "! all(%d)=%d\n", u, ret );
return ret;
}
inline void pushad( const int u, const int i, const int v ) {
f[u][i].fi = mul( f[u][i].fi, v );
if ( f[u][i].se ) f[u][i].se = mul( f[u][i].se, v );
else f[u][i].se = v;
}
inline void pushdn( const int u, const int i ) {
if ( f[u][i].se ) {
if ( i < mxd[u] ) pushad( u, i + 1, f[u][i].se );
f[u][i].se = 0;
}
}
inline void solve( const int u, const int fa, PII* curf ) {
f[u] = curf != NULL ? curf : alloc( mxd[u] + 1 );
f[u][0].fi = 1;
if ( son[u] ) solve( son[u], u, f[u] + 1 );
pushdn( u, 0 );
for ( int i = head[u], v; i; i = graph[i].nxt ) {
if ( ( v = graph[i].to ) != fa && v != son[u] ) {
solve( v, u, NULL );
int vpre = 0, upre = 1;
rep ( j, 0, mxd[v] ) {
pushdn( v, j ), pushdn( u, j + 1 );
if ( j <= mxd[v] ) vpre = add( vpre, f[v][j].fi );
int t = f[u][j + 1].fi;
f[u][j + 1].fi = add( mul( upre, f[v][j].fi ),
mul( f[u][j + 1].fi, add( vpre, 1 ) ) );
upre = add( upre, t );
}
if ( mxd[v] + 2 <= mxd[u] ) {
pushad( u, mxd[v] + 2, add( vpre, 1 ) );
}
}
}
}
inline void allClear() {
// mxd, son cleared in init.
ecnt = 0;
rep ( i, 1, n ) head[i] = 0;
for ( PII *p = pool; p <= top; *p++ = {} );
top = pool;
}
int main() {
freopen( "game.in", "r", stdin );
freopen( "game.out", "w", stdout );
for ( int T = rint(); T--; ) {
n = rint(), allClear();
rep ( i, 2, n ) link( rint(), rint() );
int all = init( 1, 0 ), del = 0;
for ( int i = head[1], v; i; i = graph[i].nxt ) {
solve( v = graph[i].to, 1, NULL );
rt.push_back( v );
rep ( j, 0, mxd[v] - 1 ) pushdn( v, j );
}
// printf( "! all=%d\n", all );
int las = 1;
rep ( i, 0, mxd[1] - 1 ) {
for ( int u: rt ) {
int k = !i ? 1 :
mul( las, mpow( add( f[u][i - 1].fi, 1 ), MOD - 2 ) );
del = add( del, mul( k, f[u][i].fi ) );
if ( i ) f[u][i].fi = add( f[u][i].fi, f[u][i - 1].fi );
}
for ( auto it( rt.begin() ); it != rt.end(); ) {
if ( i ) {
las = mul( las,
mpow( add( f[*it][i - 1].fi, 1 ), MOD - 2 ) );
}
las = mul( las, add( f[*it][i].fi, 1 ) );
if ( mxd[*it] == i ) it = rt.erase( it );
else ++it;
}
}
printf( "%d\n", sub( all, del ) );
}
return 0;
}
\(\mathcal{Details}\)
也不是说代码能力差吧,为什么我总能写那么长呢。
赛时代码比较狰狞(?)可以理解,但尽量先细致地过一遍代码流程,尽量写下来,确认无误再动手。
Solution -「多校联训」博弈的更多相关文章
- Solution -「多校联训」取石子游戏
\(\mathcal{Description}\) Link. 有 \(n\) 堆石子,第 \(i\) 堆有 \(x_i\) 个,Alice 每次只能从这堆中拿走 \(a_i\) 个石子,Bo ...
- Solution -「多校联训」排水系统
\(\mathcal{Description}\) Link. 在 NOIP 2020 A 的基础上,每条边赋权值 \(a_i\),随机恰好一条边断掉,第 \(i\) 条段的概率正比于 \(a ...
- Solution -「多校联训」I Love Random
\(\mathcal{Description}\) 给定排列 \(\{p_n\}\),可以在其上进行若干次操作,每次选取 \([l,r]\),把其中所有元素变为原区间最小值,求能够得到的所有不同序 ...
- Solution -「多校联训」签到题
\(\mathcal{Description}\) Link. 给定二分图 \(G=(X\cup Y,E)\),求对于边的一个染色 \(f:E\rightarrow\{1,2,\dots,c\ ...
- Solution -「多校联训」朝鲜时蔬
\(\mathcal{Description}\) Link. 破案了,朝鲜时蔬 = 超现实树!(指写得像那什么一样的题面. 对于整数集 \(X\),定义其 好子集 为满足 \(Y\sub ...
- Solution -「多校联训」消失的运算符
\(\mathcal{Description}\) Link. 给定长度为 \(n\) 的合法表达式序列 \(s\),其中数字仅有一位正数,运算符仅有 - 作为占位.求将其中恰好 \(k\) ...
- Solution -「多校联训」假人
\(\mathcal{Description}\) Link. 一种物品有 长度 和 权值 两种属性,现给定 \(n\) 组物品,第 \(i\) 组有 \(k_i\) 个,分别为 \((1,a ...
- Solution -「多校联训」古老的序列问题
\(\mathcal{Description}\) Link. 给定序列 \(\{a_n\}\),和 \(q\) 次形如 \([L,R]\) 的询问,每次回答 \[\sum_{[l,r]\su ...
- Solution -「多校联训」Sample
\(\mathcal{Description}\) Link (稍作简化:)对于变量 \(p_{1..n}\),满足 \(p_i\in[0,1],~\sum p_i=1\) 时,求 \(\ma ...
随机推荐
- ch01系统基础信息模块详解
第1章 系统基础信息模块详解 1.1 系统性能信息模块 psutil 解决VMWare在Windows10的安装问题: 安装VC Redistributable 2017 解决虚拟机的上网问题:修改V ...
- Word2010制作自动目录
原文链接:https://www.toutiao.com/i6488296610873737741/ 原文从网上复制: 查看"开始"选项卡,"样式"功能组,我们 ...
- vue3.0+vite+ts项目搭建-postcss-pxtorem 实现移动自适应(五)
这里不考虑大屏,所以不做amfe-flexible的配置 首先是安装依赖 yarn add postcss-loader postcss-pxtorem -D yarn add autoprefixe ...
- SYCOJ137斜线输出(1)
题目-斜线输出(1) (shiyancang.cn) 在同一斜线上的满足方程.坐标关系计算即可. #include<bits/stdc++.h> using namespace std; ...
- 【Android】安卓四大组件之Activity(二)
[Android]安卓四大组件之Activity(二) 前言 在这篇文章之前,我已经写过了一篇有关Activity的内容,是关于activity之间的页面跳转和数据传递,而这篇文章着重强调的是Acti ...
- MacBookPro2021 M1-MAX电脑问题锦集
MacBook2021 M1-MAXPro电脑问题锦集 问题1: 开启硬盘加密,开机闪屏 问题详述: 在系统偏好设置中,打开安全与隐私,在弹出窗口中切换到第二个页签(文件保险箱),启用文件保险箱功能, ...
- 豆瓣爬虫——通过json接口获取数据
最近在复习resqusts 爬虫模块,就重新写了一个豆瓣爬虫,这个网页从HTML 源码上来看是没有任何我想要的信息的,如下图所示: 这是网页视图,我在源码中查找影片信息,没有任何信息,如图: 由此我判 ...
- LSM树以及在hbase中的应用
转自:http://www.cnblogs.com/yanghuahui/p/3483754.html 讲LSM树之前,需要提下三种基本的存储引擎,这样才能清楚LSM树的由来: 哈希存储引擎 是哈希 ...
- GitHub pages+自定义域名(腾讯云域名)+cloudflare加速
本人也是第一次走完整个流程,github pages当然一直有使用,创建也很简单,并且网上教程也比较多:然后是关于自定义域名的问题,自己以前使用过国外的免费域名,然后是直接修改就ok了,然后这次使用了 ...
- Java 将PDF转为HTML时保存到流
本文介绍如何通过Java后端程序代码将PDF文件转为HTML,并将转换后的HTML文件保存到流.在实现转换时,可设置相关转换属性,如:是否嵌入SVG.是否嵌入图片等.下面是实现转换的方法和步骤: 1. ...