\(\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 -「多校联训」博弈的更多相关文章

  1. Solution -「多校联训」取石子游戏

    \(\mathcal{Description}\)   Link.   有 \(n\) 堆石子,第 \(i\) 堆有 \(x_i\) 个,Alice 每次只能从这堆中拿走 \(a_i\) 个石子,Bo ...

  2. Solution -「多校联训」排水系统

    \(\mathcal{Description}\)   Link.   在 NOIP 2020 A 的基础上,每条边赋权值 \(a_i\),随机恰好一条边断掉,第 \(i\) 条段的概率正比于 \(a ...

  3. Solution -「多校联训」I Love Random

    \(\mathcal{Description}\)   给定排列 \(\{p_n\}\),可以在其上进行若干次操作,每次选取 \([l,r]\),把其中所有元素变为原区间最小值,求能够得到的所有不同序 ...

  4. Solution -「多校联训」签到题

    \(\mathcal{Description}\)   Link.   给定二分图 \(G=(X\cup Y,E)\),求对于边的一个染色 \(f:E\rightarrow\{1,2,\dots,c\ ...

  5. Solution -「多校联训」朝鲜时蔬

    \(\mathcal{Description}\)   Link.   破案了,朝鲜时蔬 = 超现实树!(指写得像那什么一样的题面.   对于整数集 \(X\),定义其 好子集 为满足 \(Y\sub ...

  6. Solution -「多校联训」消失的运算符

    \(\mathcal{Description}\)   Link.   给定长度为 \(n\) 的合法表达式序列 \(s\),其中数字仅有一位正数,运算符仅有 - 作为占位.求将其中恰好 \(k\) ...

  7. Solution -「多校联训」假人

    \(\mathcal{Description}\)   Link.   一种物品有 长度 和 权值 两种属性,现给定 \(n\) 组物品,第 \(i\) 组有 \(k_i\) 个,分别为 \((1,a ...

  8. Solution -「多校联训」古老的序列问题

    \(\mathcal{Description}\)   Link.   给定序列 \(\{a_n\}\),和 \(q\) 次形如 \([L,R]\) 的询问,每次回答 \[\sum_{[l,r]\su ...

  9. Solution -「多校联训」Sample

    \(\mathcal{Description}\)   Link   (稍作简化:)对于变量 \(p_{1..n}\),满足 \(p_i\in[0,1],~\sum p_i=1\) 时,求 \(\ma ...

随机推荐

  1. ch01系统基础信息模块详解

    第1章 系统基础信息模块详解 1.1 系统性能信息模块 psutil 解决VMWare在Windows10的安装问题: 安装VC Redistributable 2017 解决虚拟机的上网问题:修改V ...

  2. Word2010制作自动目录

    原文链接:https://www.toutiao.com/i6488296610873737741/ 原文从网上复制: 查看"开始"选项卡,"样式"功能组,我们 ...

  3. vue3.0+vite+ts项目搭建-postcss-pxtorem 实现移动自适应(五)

    这里不考虑大屏,所以不做amfe-flexible的配置 首先是安装依赖 yarn add postcss-loader postcss-pxtorem -D yarn add autoprefixe ...

  4. SYCOJ137斜线输出(1)

    题目-斜线输出(1) (shiyancang.cn) 在同一斜线上的满足方程.坐标关系计算即可. #include<bits/stdc++.h> using namespace std; ...

  5. 【Android】安卓四大组件之Activity(二)

    [Android]安卓四大组件之Activity(二) 前言 在这篇文章之前,我已经写过了一篇有关Activity的内容,是关于activity之间的页面跳转和数据传递,而这篇文章着重强调的是Acti ...

  6. MacBookPro2021 M1-MAX电脑问题锦集

    MacBook2021 M1-MAXPro电脑问题锦集 问题1: 开启硬盘加密,开机闪屏 问题详述: 在系统偏好设置中,打开安全与隐私,在弹出窗口中切换到第二个页签(文件保险箱),启用文件保险箱功能, ...

  7. 豆瓣爬虫——通过json接口获取数据

    最近在复习resqusts 爬虫模块,就重新写了一个豆瓣爬虫,这个网页从HTML 源码上来看是没有任何我想要的信息的,如下图所示: 这是网页视图,我在源码中查找影片信息,没有任何信息,如图: 由此我判 ...

  8. LSM树以及在hbase中的应用

    转自:http://www.cnblogs.com/yanghuahui/p/3483754.html 讲LSM树之前,需要提下三种基本的存储引擎,这样才能清楚LSM树的由来: 哈希存储引擎  是哈希 ...

  9. GitHub pages+自定义域名(腾讯云域名)+cloudflare加速

    本人也是第一次走完整个流程,github pages当然一直有使用,创建也很简单,并且网上教程也比较多:然后是关于自定义域名的问题,自己以前使用过国外的免费域名,然后是直接修改就ok了,然后这次使用了 ...

  10. Java 将PDF转为HTML时保存到流

    本文介绍如何通过Java后端程序代码将PDF文件转为HTML,并将转换后的HTML文件保存到流.在实现转换时,可设置相关转换属性,如:是否嵌入SVG.是否嵌入图片等.下面是实现转换的方法和步骤: 1. ...