【题目】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的更多相关文章

  1. 【AtCoder】ARC086

    C - Not so Diverse 题解 选出现次数K多的出来,剩下的都删除即可 代码 #include <bits/stdc++.h> #define fi first #define ...

  2. 【AtCoder】ARC092 D - Two Sequences

    [题目]AtCoder Regular Contest 092 D - Two Sequences [题意]给定n个数的数组A和数组B,求所有A[i]+B[j]的异或和(1<=i,j<=n ...

  3. 【Atcoder】CODE FESTIVAL 2017 qual A D - Four Coloring

    [题意]给定h,w,d,要求构造矩阵h*w满足任意两个曼哈顿距离为d的点都不同色,染四色. [算法]结论+矩阵变换 [题解] 曼哈顿距离是一个立着的正方形,不方便处理.d=|xi-xj|+|yi-yj ...

  4. 【AtCoder】ARC 081 E - Don't Be a Subsequence

    [题意]给定长度为n(<=2*10^5)的字符串,求最短的字典序最小的非子序列字符串. http://arc081.contest.atcoder.jp/tasks/arc081_c [算法]字 ...

  5. 【AtCoder】AGC022 F - Leftmost Ball 计数DP

    [题目]F - Leftmost Ball [题意]给定n种颜色的球各k个,每次以任意顺序排列所有球并将每种颜色最左端的球染成颜色0,求有多少种不同的颜色排列.n,k<=2000. [算法]计数 ...

  6. 【AtCoder】AGC005 F - Many Easy Problems 排列组合+NTT

    [题目]F - Many Easy Problems [题意]给定n个点的树,定义S为大小为k的点集,则f(S)为最小的包含点集S的连通块大小,求k=1~n时的所有点集f(S)的和取模92484403 ...

  7. 【AtCoder】ARC067 F - Yakiniku Restaurants 单调栈+矩阵差分

    [题目]F - Yakiniku Restaurants [题意]给定n和m,有n个饭店和m张票,给出Ai表示从饭店i到i+1的距离,给出矩阵B(i,j)表示在第i家饭店使用票j的收益,求任选起点和终 ...

  8. 【AtCoder】ARC095 E - Symmetric Grid 模拟

    [题目]E - Symmetric Grid [题意]给定n*m的小写字母矩阵,求是否能通过若干行互换和列互换使得矩阵中心对称.n,m<=12. [算法]模拟 [题解]首先行列操作独立,如果已确 ...

  9. 【Atcoder】AGC022 C - Remainder Game 搜索

    [题目]C - Remainder Game [题意]给定n个数字的序列A,每次可以选择一个数字k并选择一些数字对k取模,花费2^k的代价.要求最终变成序列B,求最小代价或无解.n<=50,0& ...

随机推荐

  1. HashMap和HashTable源码分析

    HashMap HashMap是一个实现了Map接口的Hash表.提供所有Map的操作,并且允许null key和null value.HashMap几乎等同于HashTable,只不过HashMap ...

  2. 第六章 过滤器Filter

    Filter概述 Filter不用于客户端请求,只用于对request,response进行修改或对context,session,request事件进行监听. 1.概述 如上图,多个filter组成 ...

  3. caffe神经网络模型的绘图

    Python/draw_net.py, 这个文件,就是用来绘制网络模型的.也就是将网络模型由prototxt变成一张图片. 1.安装GraphViz # sudo apt-get install Gr ...

  4. 【第二周】关于java.util包下的Random类

    1.功能:此类的实例用于生成伪随机数流 2.方法(Random的方法有很多,在此只解释说明我认为比较常用的几个方法) (1)next(int bits):生成下一个伪随机数 (2)nextDouble ...

  5. scrum站立会议介绍

    什么是站立会议? 站立会议是敏捷软件开发方法论Scrum的相关技术之一,亦可称之为Scrum的最佳实践.具体形式为每天的同一时间,一个敏捷开发团队的所有成员面对面站在一起,进行一个为期15~20分钟的 ...

  6. [ Selenium2 从零开始 by Bruce from http://seleniumcn.cn ] 1-8 视频集锦

    内容转自: http://blog.csdn.net/sxl0727tu/article/details/51887093\ ************************************* ...

  7. 赋予Winform程序管理员访问权限

    业务场景:Winform操作系统盘文件夹时进行文件的读写时,会需要管理员权限打开文件. 解决方案: 在项目文件中找到app.manifest文件打开. 替换requestedExecutionLeve ...

  8. Delphi 组件渐进开发浅谈(一)——由简入繁

    最近业余时间在写游戏修改器玩,对于Delphi自带的组件总觉得差强人意,需要书写大量冗余代码,如果大量使用第三方组件,在以后的移植和与他人交互时也不是很方便,因此便产生了自己封装组件的想法. 实际上这 ...

  9. hive表信息查询:查看表结构、表操作等--转

    原文地址:http://www.aboutyun.com/forum.PHP?mod=viewthread&tid=8590&highlight=Hive 问题导读:1.如何查看hiv ...

  10. BZOJ 1190 梦幻岛宝珠(分组01背包)

    跑了7000ms... 这是个体积和价值都超大的背包.但是体积保证为a*2^b的(a<=10,b<=30)形式.且n<=100. 于是可以想到按b来分组.这样的话每组最多为a*n*2 ...