【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& ...
随机推荐
- HTML图片标签
<body> <!-- 使用img标签来向网页中引入外部的图片, img标签也是一个自结束标签 属性: src:设置一个外部图片的路径 alt:可以用来设置图片不能显示时,就会显示图 ...
- 《高性能JavaScript》学习笔记——日更中
------------------2016-7-20更------------------ 最近在看<高性能JavaScript>一书,里面当中,有讲很多提高js性能的书,正在看的过程中 ...
- java 基础 --集合--013
1, contains()方法底层依赖的是equals()方法,而定义的类中没有equal()方法,所以它会使用父类Object中的equals()方法,而Object的equals()方法比较的是地 ...
- solrCloud源码分析之CloudSolrClient
CloudSolrClient是solrj提供的客户端与solrCloud交互的类.该类的实例与zookeeper进行通信来确定solrCloud collections中的solr endpoint ...
- Eclipse 保存代码时,不自动换行设置
Eclipse在保存代码时,总是自动换行.尤其是注释,换行后的注释读起来就很混乱.后来发现是在保存文件时设置了自动格式化代码的原因. 关闭自动格式代码设置: windows-->Preferen ...
- 洛谷 P1401 城市(二分+网络流)
题目描述 N(2<=n<=200)个城市,M(1<=m<=40000)条无向边,你要找T(1<=T<=200)条从城市1到城市N的路,使得最长的边的长度最小,边不能 ...
- NHibernate 设置主键不自增长
1.Model 配置 [PrimaryKey(PrimaryKeyType.Assigned,"ID")] 2.使用时要手动赋值
- secureCRT mac 下破解
http://blog.csdn.net/skykingf/article/details/17450561
- [POI2008]MAF-Mafia
Description 有n个人,每个人手里有一把手枪.一开始所有人都选定一个人瞄准(有可能瞄准自己).然后他们按某个顺序开枪,且任意时刻只有一个人开枪.因此,对于不同的开枪顺序,最后死的人也不同. ...
- python的复制,深拷贝和浅拷贝的区别(转)
在python中,对象赋值实际上是对象的引用.当创建一个对象,然后把它赋给另一个变量的时候,python并没有拷贝这个对象,而只是拷贝了这个对象的引用 一般有三种方法, alist=[1,2,3,[& ...