码迷,mamicode.com
首页 > 其他好文 > 详细

ARC_086_E Smuggling Marbles

时间:2017-12-16 18:40:51      阅读:175      评论:0      收藏:0      [点我收藏+]

标签:最大的   each   sigma   return   cli   ret   state   表示   复杂度   

E - Smuggling Marbles


Time limit : 3sec / Memory limit : 512MB

Score : 1000 points

Problem Statement

Snuke has a rooted tree with N+1 vertices. The vertices are numbered 0 through N, and Vertex 0 is the root of the tree. The parent of Vertex i(1≤iN) is Vertexpi.

Besides this tree, Snuke also has an box which is initially empty and many marbles, and playing with them. The play begins with placing one marble on some of the vertices, then proceeds as follows:

  1. If there is a marble on Vertex 0, move the marble into the box.
  2. Move each marble from the vertex to its parent (all at once).
  3. For each vertex occupied by two or more marbles, remove all the marbles from the vertex.
  4. If there exists a vertex with some marbles, go to Step 1. Otherwise, end the play.

There are 2N+1 ways to place marbles on some of the vertices. For each of them, find the number of marbles that will be in the box at the end of the play, and compute the sum of all those numbers modulo 1,000,000,007.

Constraints

  • 1≤N<2×105
  • 0≤pi<i

Partial Scores

  • In the test set worth 400 points, N<2,000.

Input

Input is given from Standard Input in the following format:

Np1p2pN

Output

Print the answer.


Sample Input 1

2
0 0

Sample Output 1

8

When we place a marble on both Vertex 1 and 2, there will be multiple marbles on Vertex 0 by step 2. In such a case, these marbles will be removed instead of being moved to the box.


Sample Input 2

5
0 1 1 0 4

Sample Output 2

96

Sample Input 3

31
0 1 0 2 4 0 4 1 6 4 3 9 7 3 7 2 15 6 12 10 12 16 5 3 20 1 25 20 23 24 23

Sample Output 3

730395550

Be sure to compute the sum modulo 1,000,000,007.

【题意】

给定n+1个点的树(root=0),每个点可以选择放或不放弹珠,每一轮顺序进行以下操作:

1.将根节点0的弹珠加入答案。

2.每个点的弹珠移向父亲。

3.如果一个点有超过2个弹珠,全部丢掉。

如果树中仍有弹珠,继续下一轮。

共有2^(n+1)种放弹珠的方案,计算所有方案的答案之和,取模1e9+7。

n<=2*10^5。(部分分:n<=2*10^3)

【题解】

虽然有人说官方题解Editorial写得很好,但是本人由于太蒟蒻因此没看懂,靠看各路大神的程序勉强理解了官方的做法

容易发现,层与层之间互相独立,第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)。

我原以为会超内存,后来发现最大的内存占用约为200000kb,题目限制512mb也就是约500000kb,不会爆

 

技术分享图片
 1 //arc_086 E
 2 const int mod=1e9+7;
 3 
 4 struct tri{
 5     int a,b,c;    //分别代表使得当前节点上珠子数为0,1,2+的种数 
 6     tri(int x,int y,int z){
 7         a=x;
 8         b=y;
 9         c=z;
10     }
11 };
12 
13 int n;
14 vector<int> adj[222222];
15 int nums[222222];    //记录某一层中的节点数目
16 int dep[222222];    //记录顶点的深度
17 deque<tri> dp[222222];
18 
19 void dfs(int nw){
20     nums[dep[nw]]++;
21     for(int i=0;i<adj[nw].size();i++){
22         int v=adj[nw][i];
23         dep[v]=dep[nw]+1;
24         dfs(v);
25     }
26 }
27 
28 void solve(int nw){
29     for(int i=0;i<adj[nw].size();i++){
30         int v=adj[nw][i];
31         solve(v);
32         if(dp[v].size()>dp[nw].size()) swap(dp[v],dp[nw]);
33     }
34     
35     int mx=0;
36     int ansa=0,ansb=0,ansc=0;
37     for(int i=0;i<adj[nw].size();i++){
38         int v=adj[nw][i];
39         mx=max(mx,(int)dp[v].size());
40         for(int j=0;j<dp[v].size();j++){
41             ansa=(dp[nw][j].a*1ll*dp[v][j].a)%mod;
42             ansb=(dp[nw][j].a*1ll*dp[v][j].b+dp[nw][j].b*1ll*dp[v][j].a)%mod;
43             ansc=(dp[nw][j].b*1ll*dp[v][j].b+dp[nw][j].c*1ll*(dp[v][j].a+dp[v][j].b))%mod;
44             tri t(ansa,ansb,ansc);
45             dp[nw][j]=t;
46         }
47     }
48     
49     for(int i=0;i<mx;i++){
50         dp[nw][i].a+=dp[nw][i].c;
51         dp[nw][i].a%=mod;
52         dp[nw][i].c=0;
53     }
54     
55     dp[nw].push_front(tri(1,1,0));
56 }
57 
58 int pw[222222];
59 void calc(){
60     pw[0]=1;
61     for(int i=1;i<=200000;i++){
62         pw[i]=pw[i-1]*2;
63         if(pw[i]>mod) pw[i]-=mod;
64     }
65 }
66 
67 int main(){
68     calc();
69     n=read();
70     for(int i=1;i<=n;i++){
71         int x=read();
72         adj[x].pb(i);
73     }
74     
75     dfs(0);
76     solve(0);
77     
78     int ans=0;
79     for(int i=0;i<dp[0].size();i++){
80     //    cout<<dp[0][i].b<<‘ ‘<<pw[n+1-nums[i]]<<endl;
81         ans+=dp[0][i].b*1ll*pw[n+1-nums[i]]%mod;
82         ans%=mod;
83     }
84     
85     cout<<ans<<endl;
86     return 0;
87 }
View Code

 

ARC_086_E Smuggling Marbles

标签:最大的   each   sigma   return   cli   ret   state   表示   复杂度   

原文地址:http://www.cnblogs.com/nflslzt/p/8046982.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!