【AtCoder】ARC086 E - Smuggling Marbles
【题意】给定n+1个点的树(root=0),每个点可以选择放或不放弹珠,每一轮顺序进行以下操作:
1.将根节点0的弹珠加入答案。
2.每个点的弹珠移向父亲。
3.如果一个点有超过2个弹珠,全部丢掉。
如果树中仍有弹珠,继续下一轮。
共有2^(n+1)种放弹珠的方案,计算所有方案的答案之和,取模1e9+7。
n<=2*10^5。(部分分:n<=2*10^3)
【算法】树形DP
【题解】容易发现,层与层之间互相独立,第i轮只需要考虑第i层的节点组合的子集中有多少个子集能到达0点,加起来就是总答案。
接下来考虑每轮进行一次树形DP,为了方便求解集合交,将方案计算转化为概率计算(集合交就是概率的乘积),则每个点有弹珠的概率是1/2。
令f[i][j]表示节点i有j个弹珠(j=0,1)的概率,则有:
f[i][1]=Σs/f[j][0]*f[j][1],s=Πf[j][0],j=son(i)
f[i][0]=1-f[i][1]
每一轮将对应深度的点全部初始化为1/2,然后树形DP到根就可以得到答案,复杂度O(n^2),400分。
考虑将一个点在多轮的情况都考虑起来,f[i][d][j]表示点i在第d轮有j个弹珠的概率(j=0,1,2,2代表>=2)。
令f[i][d]={f[i][d][0],f[i][d][1],f[i][d][2]},即视为一个状态,对于同轮(同深度同d)的两个状态可以合并(两个状态对应9种交集,交集乘 后 并集加)
对于一个点要将其所有儿子合并,两个点合并只需将0~min(d1,d2)的状态对应合并,以d大的点作为基础来合并(不要复制)。
那么初始状态为f[i][0]={1/2,1/2,0},对于每个点将其儿子全部合并,然后顺推一位将d=0设为初始状态,最后记得将状态中的2搬到0处,注意这个过程必须只搬有改动的状态才能保证复杂度(之前不能直接归为0是因为在儿子的合并中2和0有区别)
复杂度分析同线段树合并,O(n)。
唔……真的挺难说清楚的,推荐原题解Editorial,把这篇当作简单的翻译就好了。
#include<cstdio>
#include<cstring>
#include<cctype>
#include<vector>
#include<algorithm>
using namespace std;
const int maxn=,MOD=;
int read(){
char c;int s=,t=;
while(!isdigit(c=getchar()))if(c=='-')t=-;
do{s=s*+c-'';}while(isdigit(c=getchar()));
return s*t;
}
struct cyc{
int z0,z1,z2;
};
cyc operator + (cyc a,cyc b){
cyc c;
c.z0=1ll*a.z0*b.z0%MOD;
c.z1=(1ll*a.z0*b.z1+1ll*a.z1*b.z0)%MOD;
c.z2=(1ll*a.z0*b.z2+1ll*a.z2*b.z0+1ll*a.z1*b.z1+1ll*a.z2*b.z2+1ll*a.z1*b.z2+1ll*a.z2*b.z1)%MOD;
return c;
}
vector<cyc>a[maxn];
int n,fa[maxn],first[maxn],cnt=,tot=,b[maxn];
struct edge{int v,from;}e[maxn*];
void insert(int u,int v){cnt++;e[cnt].v=v;e[cnt].from=first[u];first[u]=cnt;}
int MO(int x){return x>=MOD?x-MOD:x;}
void merge(int &x,int y){
if(a[x].size()<a[y].size())swap(x,y);
for(int i=;i<(int)a[y].size();i++){
a[x][a[x].size()-i-]=a[x][a[x].size()-i-]+a[y][a[y].size()-i-];
}
}
int main(){
n=read()+;
for(int i=;i<=n;i++)fa[i]=read()+,insert(fa[i],i);
for(int i=n;i>=;i--){
int mx=;
if(!first[i]){
a[b[i]=++tot].push_back((cyc){(MOD+)/,(MOD+)/,});
}
else{
b[i]=b[e[first[i]].v];
for(int j=e[first[i]].from;j;j=e[j].from){
mx=max(mx,min((int)a[b[i]].size(),(int)a[b[e[j].v]].size()));
merge(b[i],b[e[j].v]);
}
a[b[i]].push_back((cyc){(MOD+)/,(MOD+)/,});
}
for(int j=(int)a[b[i]].size()--;j>=(int)a[b[i]].size()-mx-;j--)a[b[i]][j].z0+=a[b[i]][j].z2,a[b[i]][j].z2=;
}
int ans=,N=;
for(int i=;i<=n;i++)N=(N<<)%MOD;
for(int i=;i<(int)a[b[]].size();i++)ans=MO(ans+1ll*a[b[]][i].z1*N%MOD);
printf("%d",ans);
return ;
}
【AtCoder】ARC086 E - Smuggling Marbles的更多相关文章
- 【AtCoder】ARC086
C - Not so Diverse 题解 选出现次数K多的出来,剩下的都删除即可 代码 #include <bits/stdc++.h> #define fi first #define ...
- 【AtCoder】ARC092 D - Two Sequences
[题目]AtCoder Regular Contest 092 D - Two Sequences [题意]给定n个数的数组A和数组B,求所有A[i]+B[j]的异或和(1<=i,j<=n ...
- 【Atcoder】CODE FESTIVAL 2017 qual A D - Four Coloring
[题意]给定h,w,d,要求构造矩阵h*w满足任意两个曼哈顿距离为d的点都不同色,染四色. [算法]结论+矩阵变换 [题解] 曼哈顿距离是一个立着的正方形,不方便处理.d=|xi-xj|+|yi-yj ...
- 【AtCoder】ARC 081 E - Don't Be a Subsequence
[题意]给定长度为n(<=2*10^5)的字符串,求最短的字典序最小的非子序列字符串. http://arc081.contest.atcoder.jp/tasks/arc081_c [算法]字 ...
- 【AtCoder】AGC022 F - Leftmost Ball 计数DP
[题目]F - Leftmost Ball [题意]给定n种颜色的球各k个,每次以任意顺序排列所有球并将每种颜色最左端的球染成颜色0,求有多少种不同的颜色排列.n,k<=2000. [算法]计数 ...
- 【AtCoder】AGC005 F - Many Easy Problems 排列组合+NTT
[题目]F - Many Easy Problems [题意]给定n个点的树,定义S为大小为k的点集,则f(S)为最小的包含点集S的连通块大小,求k=1~n时的所有点集f(S)的和取模92484403 ...
- 【AtCoder】ARC067 F - Yakiniku Restaurants 单调栈+矩阵差分
[题目]F - Yakiniku Restaurants [题意]给定n和m,有n个饭店和m张票,给出Ai表示从饭店i到i+1的距离,给出矩阵B(i,j)表示在第i家饭店使用票j的收益,求任选起点和终 ...
- 【AtCoder】ARC095 E - Symmetric Grid 模拟
[题目]E - Symmetric Grid [题意]给定n*m的小写字母矩阵,求是否能通过若干行互换和列互换使得矩阵中心对称.n,m<=12. [算法]模拟 [题解]首先行列操作独立,如果已确 ...
- 【Atcoder】AGC022 C - Remainder Game 搜索
[题目]C - Remainder Game [题意]给定n个数字的序列A,每次可以选择一个数字k并选择一些数字对k取模,花费2^k的代价.要求最终变成序列B,求最小代价或无解.n<=50,0& ...
随机推荐
- lintcode-206-区间求和 I
206-区间求和 I 给定一个整数数组(下标由 0 到 n-1,其中 n 表示数组的规模),以及一个查询列表.每一个查询列表有两个整数 [start, end] . 对于每个查询,计算出数组中从下标 ...
- EF 联合查询
EF 文章表和标签表联合查询标签id在dis中的文章,还不知道性能如何 var query = tagRepo.Entities.Include("Tags").Where(t = ...
- DNS服务器的解析
---恢复内容开始--- DNS前言: 英特网作为域名和IP地址相互映射的一个分不式数据库,能够使用户更方便的访问互联网.而不用去记住能够被机器直接读取的IP地址的过程叫做域名解析(或主机名解析).D ...
- webpack打包多html开发案例新
闲来无事在原来简单打包案例的基础上,参考vue-cli的打包代码,改为多文件打包. 区别于上篇文章<webpack打包多html开发案例>,此次打包根据开发的不同环节进行打包,也就是有开发 ...
- Git命令常用清单
本文从以下十个方面,介绍Git命令的常用清单: 一.新建代码库 二.配置 三.增加/删除文件 四.代码提交 五.分支 六.标签 七.查看信息 八.远程同步 九.撤销 十.其他 每天使用 Git ,但是 ...
- JS在当前页面插入<script>标签,并执行
将<script>标签绑定到<html>上, html可换成body,header等其他存在的标签. var htmm =document.getElementsByTagNa ...
- MacOS & 如何在当前文件下打开 terminal
MacOS & 如何在当前文件下打开 terminal macbook 如何在文件夹中 打开 terminal https://www.cnblogs.com/yjmyzz/p/3662507 ...
- Spring异步事件
1.发布事件 @Data public class CustomEvent extends ApplicationEvent implements Serializable { private Boo ...
- 【转】WinForms 使用Graphics绘制字体阴影
转自:http://www.cnblogs.com/LonelyShadow/p/3893743.html C#以两种方法实现文字阴影效果,同时还实现了简单的动画效果: 一种是对文本使用去锯齿的边缘处 ...
- THUSC2018滚粗记
THUSC2018滚粗记 前言 大家好,我是\(yyb\),我的博客里又多了一篇滚粗记, 我记得我原来在某篇滚粗记中曾经写过 \(yyb\)还会写很多很多次滚粗记才会有一篇不是滚粗记的东西. 看起来这 ...