[树形DP] 51Nod1500 苹果曼和树

来源:互联网 发布:乐其网络 编辑:程序博客网 时间:2024/06/05 05:28

简单的树形 DP 。记 fi,0/1 表示考虑以 i 为根的子树,所在的块有一个黑或没有黑结点的方案数。
转移很显然。

#include<cstdio>#include<algorithm>using namespace std;typedef long long LL;const int maxn=100005,maxe=100005,MOD=1000000007;int n,c[maxn];LL f[maxn][2];int fir[maxn],nxt[maxe],son[maxe],tot;void add(int x,int y){    son[++tot]=y; nxt[tot]=fir[x]; fir[x]=tot;}LL Pow(LL a,int b){    LL res=1; a%=MOD;    for(;b;b>>=1,a=a*a%MOD) if(b&1) res=(res*a)%MOD;    return res;}void dfs(int x){    LL all0=1;    for(int j=fir[x];j;j=nxt[j]) dfs(son[j]), (all0*=(f[son[j]][0]+f[son[j]][1])%MOD)%=MOD;    if(c[x]) f[x][1]=all0, f[x][0]=0; else{        f[x][0]=all0;        for(int j=fir[x];j;j=nxt[j]) (f[x][1]+=all0*Pow(f[son[j]][0]+f[son[j]][1],MOD-2)%MOD*f[son[j]][1]%MOD)%=MOD;    }}int main(){    freopen("51nod1500.in","r",stdin);    freopen("51nod1500.out","w",stdout);    scanf("%d",&n);    for(int i=2;i<=n;i++){        int x; scanf("%d",&x);        add(x+1,i);    }    for(int i=1;i<=n;i++) scanf("%d",&c[i]);    dfs(1);    printf("%d\n",f[1][1]);    return 0;} 
原创粉丝点击