1. 程式人生 > >【AtCoder】ARC086 E - Smuggling Marbles

【AtCoder】ARC086 E - Smuggling Marbles

closed getchar 一輪 oot pre ring tor i++ cto

【題目】E - Smuggling Marbles

【題意】給定n+1個點的樹(root=0),每個點可以選擇放或不放彈珠,每一輪進行四個操作:

1.將根節點0的彈珠加入答案。

2.每個點的彈珠移向父親。

3.如果一個點有超過2個彈珠,全部丟掉。

如果樹中仍有彈珠,繼續下一輪。

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

n<=2*10^5。

【算法】樹形DP

【題解】

技術分享圖片
#include<cstdio>
#include<cstring>
#include<cctype>
#include<vector>
#include
<algorithm> using namespace std; const int maxn=200010,MOD=1000000007; int read(){ char c;int s=0,t=1; while(!isdigit(c=getchar()))if(c==-)t=-1; do{s=s*10+c-0;}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=0,tot=0,b[maxn]; struct edge{int v,from;}e[maxn*2]; 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=0;i<(int)a[y].size();i++){ a[x][a[x].size()-i-1]=a[x][a[x].size()-i-1]+a[y][a[y].size()-i-1]; } } int main(){ n=read()+1; for(int i=2;i<=n;i++)fa[i]=read()+1,insert(fa[i],i); for(int i=n;i>=1;i--){ int mx=0; if(!first[i]){ a[b[i]=++tot].push_back((cyc){(MOD+1)/2,(MOD+1)/2,0}); } 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+1)/2,(MOD+1)/2,0}); } for(int j=(int)a[b[i]].size()-1-1;j>=(int)a[b[i]].size()-mx-1;j--)a[b[i]][j].z0+=a[b[i]][j].z2,a[b[i]][j].z2=0; } int ans=0,N=1; for(int i=1;i<=n;i++)N=(N<<1)%MOD; for(int i=0;i<(int)a[b[1]].size();i++)ans=MO(ans+1ll*a[b[1]][i].z1*N%MOD); printf("%d",ans); return 0; }
View Code

【AtCoder】ARC086 E - Smuggling Marbles