【题目】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. Spring管理过滤器:org.springframework.web.filter.DelegatingFilterProxy

    配置web.xml <filter>        <filter-name>springSecurityFilterChain</filter-name>     ...

  2. 使用salt-cloud创建虚拟机

    salt-cloud也是基于openstack来做的,它可以支持多种云的使用.比如:Aliyun.Azure.DigitalOcean.EC2.Google Compute Engine.HP Clo ...

  3. 【C++】C++ static关键字详解

    static的作用 1.隐藏 当我们编译多个文件时,所有未加static前缀的全局变量和函数都具有全局可见性,其他的源文件也能访问.如,我们有源文件source1.cpp定义了一个全局变量i和函数Fu ...

  4. HDU 6035 Colorful Tree(dfs)

    题意:一棵有n个点的树,树上每个点都有颜色c[i],定义每条路径的值为这条路径上经过的不同颜色数量和.求所有路径的值的和. 可以把问题转化为对每种颜色有多少条不同的路径至少经过这种颜色的点,然后加和. ...

  5. 【BZOJ1226】学校食堂(动态规划,状态压缩)

    [BZOJ1226]学校食堂(动态规划,状态压缩) 题面 BZOJ 洛谷 题解 发现\(b\)很小,意味着当前这个人最坏情况下也只有后面的一小部分人在他前面拿到饭. 所以整个结果的大致顺序是不会变化的 ...

  6. 机器学习算法的Python实现 (1):logistics回归 与 线性判别分析(LDA)

    先收藏............ 本文为笔者在学习周志华老师的机器学习教材后,写的课后习题的的编程题.之前放在答案的博文中,现在重新进行整理,将需要实现代码的部分单独拿出来,慢慢积累.希望能写一个机器学 ...

  7. vs下取得资源文件中的版本信息

    在Windows Mobile和Wince(Windows Embedded CE)下开发的产品,有时候需要显示当前产品的版本信息.一般来说,版本信息是保存在资源文件里面的,例如下图: 为了保持一致, ...

  8. Codeforces Round #286 (Div. 2) B 并查集

    B. Mr. Kitayuta's Colorful Graph time limit per test 1 second memory limit per test 256 megabytes in ...

  9. 防止xss攻击的核心代码

    public class XssFilter implements Filter { @Override public void destroy() { } /** * 过滤器用来过滤的方法 */ @ ...

  10. find~~~查找文件

    find . -name "klibc" 在当前文件内查找文件 klibc find . -name "*libc*" 在当前文件内查找文件 (模糊查询)