[题解] Atcoder ARC 142 D Deterministic Placing 结论,DP
题目
(可能有点长,但是请耐心看完,个人认为比官方题解好懂:P)
首先需要注意,对于任意节点i上的一个棋子,如果在一种走法中它走到了节点j,另一种走法中它走到了节点k,那么这两种走法进行完后,棋子占据的节点集合不可能相同,因为在这两种走法中,节点i必有两个子树中的棋子数量不同。所以,题目中的"被占据的集合唯一"等价于"每个棋子走向的节点唯一"。
根据题意,一个初始状态合法当且仅当这个状态可以进行任意次操作,且进行k步操作后,接下来一步操作唯一(不管这样走之后,是否还能进行无限次操作)。先不考虑"唯一",只考虑怎么使得可以进行无限次操作。我们可以把树分成一些链,每条链初始有一个端点是空的,其他节点都被棋子占据。第一步操作时,把每条链上的每个棋子,都往这条链上的空节点方向移动一步。后面的每一步操作都可以在这两个状态之间反复横跳,满足了"无限次"的要求。现在把"唯一"的条件加进来,发现树上的每个节点都必须恰好被一条链覆盖到,不然肯定存在一个没被覆盖的节点i,使得在某一步中可以把一个本应该走到其他位置的棋子移到这个点上,使得方案不唯一。
如果一个状态合法,唯一的操作方案就是:每条链上的棋子在这条链上左右横跳。现在来看看哪些"链划分"是不合法的(操作方案不唯一)。我们把每条链没有棋子的端点称为"0端",有棋子的端点称为"1端",这两个统称端点;其它点称为中间点。
先给出结论:两个相邻节点x、y,如果出现以下情况之一,这种状态就不合法,否则合法:1.一个是中间点,一个是端点,且属于不同的链;2.两个点都是1端(属于不同的链);3.两个点都是0端(显然也属于不同的链)。
证明:
1.出现以上情况的一定不合法
如果x是中间点且y是端点,不属于同链,如果y是1则x可以在第一步向y移动,y是0则x可以在第二步向y移动,均不唯一
都是1端,则可以合并成一条链,并扔掉其中一条链的0端,不唯一
都是0端,则移动一次后可以合并成一条链
2.不出现的一定合法
只需要证明任意一种没有上述情况的状态,第一步操作都唯一。因为操作一次后达到的状态是与其对称的,再操作一次又回到了这个状态。
考虑一个中间节点会不会不守本分,跑到其他的链去。那肯定是跑到了另一条链的一个中间节点,原本要到这个点的棋子就必须找另一条路,它可以走到另一条链,也可以向着本链的1端走一步,第一种走法循环了,所以若干次后总会走上第二种。走上第二种后,类似的,总能规约到一个1端棋子必须走到别的链(的0端)。原来要走到这个0端节点的棋子是在一个中间位置上的,它又需要走到别的链,或者向本链1端走\(\cdots\)
发现陷入了死循环,所以总有一个点找不到出路,所以方案不唯一的情况此时不会出现。
接下来对合法的链划分计数。考虑树形dp,dp过程中不考虑每条链的方向(即忽略0端和1端的位置)
dp[*][0]&:当前是中间节点,所在链的两端点都在子树内\\
dp[*][1]&:中间节点,链只有一个端点在子树内\\
dp[*][2]&:端点,与之匹配的端点不在子树内\\
dp[*][3]&:端点,匹配的端点在子树内
\end{align}
\]
转移比较简单,不一一赘述。考虑怎么加入每条链方向的影响,如果两条链端点相邻,则在这两条链间连边。最后每一个连通块都有2种方案。对于任意一个中间节点,它在树上的儿子中除了1或2个,其他都跟它属于不同的连通块,当前dp到的节点为中间节点时乘上对应方案数即可。
时间复杂度\(O(n)\)。
点个赞求求了,/kel
点击查看代码
#include <bits/stdc++.h>
#define rep(i,n) for(int i=0;i<n;++i)
#define repn(i,n) for(int i=1;i<=n;++i)
#define LL long long
#define pii pair <int,int>
#define pb push_back
#define fi first
#define se second
#define mpr make_pair
using namespace std;
const LL MOD=998244353;
LL qpow(LL x,LL a)
{
LL res=x,ret=1;
while(a>0)
{
if((a&1)==1) ret=ret*res%MOD;
a>>=1;
res=res*res%MOD;
}
return ret;
}
LL n,dp[200010][4],dp2[200010][3],suf[200010];
vector <LL> g[200010];
void dfs(LL pos,LL par)
{
vector <LL> son;
rep(i,g[pos].size()) if(g[pos][i]!=par)
{
dfs(g[pos][i],pos);
son.pb(g[pos][i]);
}
//2
dp[pos][2]=1;rep(i,son.size()) (dp[pos][2]*=dp[son[i]][3])%=MOD;
//3
suf[0]=1;rep(i,son.size()) suf[i+1]=suf[i]*dp[son[son.size()-i-1]][3]%MOD;
LL bas=1;
rep(i,son.size())
{
(dp[pos][3]+=(dp[son[i]][1]+dp[son[i]][2])%MOD*bas%MOD*suf[son.size()-i-1])%=MOD;
(bas*=dp[son[i]][3])%=MOD;
}
//1
suf[0]=1;rep(i,son.size()) suf[i+1]=suf[i]*dp[son[son.size()-i-1]][0]%MOD;
bas=1;
rep(i,son.size())
{
(dp[pos][1]+=(dp[son[i]][1]+dp[son[i]][2])%MOD*bas%MOD*suf[son.size()-i-1])%=MOD;
(bas*=dp[son[i]][0])%=MOD;
}
//0
rep(i,son.size()+3) rep(j,3) dp2[i][j]=0;
dp2[0][0]=1;
rep(i,son.size()) rep(j,3)
{
if(j<2) (dp2[i+1][j+1]+=dp2[i][j]*(dp[son[i]][1]+dp[son[i]][2]))%=MOD;
(dp2[i+1][j]+=dp2[i][j]*dp[son[i]][0])%=MOD;
}
dp[pos][0]=dp2[son.size()][2];
LL mul=(LL)son.size()-2;
if(mul>0) (dp[pos][0]*=qpow(2,mul))%=MOD;
++mul;
if(mul>0) (dp[pos][1]*=qpow(2,mul))%=MOD;
}
int main()
{
cin>>n;
LL x,y;
rep(i,n-1)
{
scanf("%lld%lld",&x,&y);
g[x].pb(y);g[y].pb(x);
}
dfs(1,0);
cout<<(dp[1][0]+dp[1][3])*2LL%MOD<<endl;
return 0;
}
[题解] Atcoder ARC 142 D Deterministic Placing 结论,DP的更多相关文章
- [题解] Atcoder ARC 142 E Pairing Wizards 最小割
题目 建图很妙,不会. 考虑每一对要求合法的巫师(x,y),他们两个的\(a\)必须都大于\(min(b_x,b_y)\).所以在输入的时候,如果\(a_x\)或者\(a_y\)小于\(min(b_x ...
- 【题解】POJ2279 Mr.Young′s Picture Permutations dp
[题解]POJ2279 Mr.Young′s Picture Permutations dp 钦定从小往大放,然后直接dp. \(dp(t1,t2,t3,t4,t5)\)代表每一行多少人,判断边界就能 ...
- 【题解】HDU4689 Derangement(有技巧的计数DP)
[题解]HDU4689 Derangement(有技巧的计数DP) 传送门 呵呵没告诉我多测组数,然后\(n\le 20,7000\mathrm{ms}\)我写了个状压上去T了 题目大意: 要你求错排 ...
- 【题解】Music Festival(树状数组优化dp)
[题解]Music Festival(树状数组优化dp) Gym - 101908F 题意:有\(n\)种节目,每种节目有起始时间和结束时间和权值.同一时刻只能看一个节目(边界不算),在所有种类都看过 ...
- 【题解】CF1056F Write the Contest(三分+贪心+DP)
[题解]CF1056F Write the Contest(三分+贪心+DP) 最优化问题的三个解决方法都套在一个题里了,真牛逼 最优解应该是怎样的,一定存在一种最优解是先完成了耗时长的任务再干别的( ...
- [题解] Atcoder Regular Contest ARC 147 A B C D E 题解
点我看题 A - Max Mod Min 非常诈骗.一开始以为要观察什么神奇的性质,后来发现直接模拟就行了.可以证明总操作次数是\(O(nlog a_i)\)的.具体就是,每次操作都会有一个数a被b取 ...
- 【题解】Atcoder ARC#96 F-Sweet Alchemy
首先,我们发现每一个节点所选择的次数不好直接算,因为要求一个节点被选择的次数大于等于父亲被选择的次数,且又要小于等于父亲被选择的次数 \(+D\).既然如此,考虑一棵差分的树,规定每一个节点被选择的次 ...
- 【题解】Atcoder ARC#90 F-Number of Digits
Atcoder刷不动的每日一题... 首先注意到一个事实:随着 \(l, r\) 的增大,\(f(r) - f(l)\) 会越来越小.考虑暴力处理出小数据的情况,我们可以发现对于左端点 \(f(l) ...
- 【题解】Atcoder ARC#94 F-Normalization
再次膜拜此强题!神级性质之不可能发现系列收藏++:首先,对于长度<=3的情况,我们采取爆搜答案(代码当中是打表).对于长度>=4的情况,则有如下几条玄妙的性质: 首先我们将 a, b, c ...
随机推荐
- excel网络函数库之谷歌翻译
不知道看到本篇文章的小伙伴是否被表格翻译所困扰,当面对大量需要被翻译的文件内容,有着三头六臂的孙悟空也难以招架得住,那么有没有一个工具能让我们快速将大量文件进行翻译呢? ExcelApi函数库的横空出 ...
- springmvc源码笔记-RequestMappingHandlerMapping
下图是springmvc的执行流程 图片来源:https://www.jianshu.com/p/8a20c547e245 DispatcherServlet根据url定位到Controller和方法 ...
- CentOS7添加swap分区
买了个云主机,只有1G内存,跑爬虫经常内存不足,于是只能添加swap来缓解: 1.官方推荐的swap大小定义 2.使用dd命令在根下创建swapfile dd if=/dev/zero of=/swa ...
- 字符输入流Reader类和FileReader和字符输入流读取字符数据
java.io.Reader:字符输入流,是字符输入流的最顶层的父类,定义了一些共性的成员方法,是一个抽象类 共性成员方法: int read();读取单个字符并返回 int read(char[] ...
- UE4.25 Slate源码解读
概述 Slate系统是UE的一套UI解决方案,UMG系统也是依赖Slate系统实现的. 问题: Slate系统是如何组织的? 控件树的父子关系是如何绑定的? Slate系统是如何渲染的? slate渲 ...
- Odoo14 自定义widget小部件
不多说先上源码. 1 odoo.define('my_company_users_widget', function (require) { 2 "use strict"; 3 4 ...
- Auto.js 特殊定位控件方法 不能在ui线程执行阻塞操作,请使用setTimeout代替
本文所有教程及源码.软件仅为技术研究.不涉及计算机信息系统功能的删除.修改.增加.干扰,更不会影响计算机信息系统的正常运行.不得将代码用于非法用途,如侵立删! Auto.js 特殊定位控件方法 操作环 ...
- BZOJ3262/Luogu3810 陌上花开 (三维偏序,CDQ)
一个下午的光阴之死,凶手是细节与手残. 致命的一枪:BIT存权值时: for(; x <= maxx; x += x&-x) t[x] += w; //for(; x <= n; ...
- day21--Java集合04
Java集合04 9.Set接口方法 Set接口基本介绍 无序(添加和取出的顺序不一致),没有索引 不允许重复元素,所以最多只有一个null JDK API中接口的实现类有: Set接口的常用方法:和 ...
- Java中字节流的总结及代码练习
Java中的字节流 在描述字节流时,先知道什么是流 流可以分为:输入流和输出流 输入流和输出流 示意图: 字节流读取内容:二进制,音频,视频 优缺点:可以保证视频音频无损,效率低,没有缓冲区 字节流可 ...