Codeforces Round #275 (Div. 1) D Random Function and Tree 树形dp

http://codeforces.com/contest/482

其实我们只需要考虑三种情况一种从左到右成立,一种从右到左成立,一种两边都成立,答案就是前两种相加减去后一种,前两种好球,后一种用dp[i][j][k]便是第i个儿子前面的取得点的个数%2后的值,后面是这个点后面的所有取得点%2后的值,然后就写完了。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
typedef long long LL;
const int maxn=100005;
const int mod=1000000007;
int dp[maxn][2];
vector<int>g[maxn];
int dp1[maxn][2][2];
int dp2[maxn][2];
void chan(int &p){
    if(p>=mod)p=p-mod;
}
void dfs(int u){
    for(int v:g[u]){
        dfs(v);
    }
    int tot=0;
    memset(dp2[0],0,sizeof(dp2[0]));
    dp2[0][0]=1;
    for(int v:g[u]){
        ++tot;
        for(int x=0;x<2;x++){
            dp2[tot][x]=dp2[tot-1][x];
        }
        for(int w=0;w<2;w++){
            for(int y=0;y<2;y++){
                dp2[tot][w^y]+=((LL)dp2[tot-1][w]*dp[v][y])%mod;
                chan(dp2[tot][w^y]);
            }
        }
    }
    dp[u][0]=dp2[tot][1];
    dp[u][1]=dp2[tot][0];
    memset(dp2[tot+1],0,sizeof(dp2[tot+1]));
    dp2[tot+1][0]=1;
    int p=g[u].size();
    for(int i=p-1;i>=0;i--){
        int v=g[u][i];
        for(int x=0;x<2;x++){
            dp2[tot][x]=dp2[tot+1][x];
        }
        for(int w=0;w<2;w++){
            for(int y=0;y<2;y++){
                dp2[tot][w^y]+=((LL)dp2[tot+1][w]*dp[v][y])%mod;
                chan(dp2[tot][w^y]);
            }
        }
        tot--;
    }
    dp[u][0]+=dp2[1][1];
    chan(dp[u][0]);
    dp[u][1]+=dp2[1][0];
    chan(dp[u][1]);
    memset(dp1[0],0,sizeof(dp1[0]));
    tot=0;
    for(int v:g[u]){
        ++tot;
        for(int x=0;x<2;x++){
            for(int y=0;y<2;y++){
                dp1[tot][x][y]=dp1[tot-1][x][y];
            }
        }
        for(int w=0;w<2;w++){
            for(int y=0;y<2;y++){
                if(w==0){
                    dp1[tot][y][w]+=dp[v][y];
                    chan(dp1[tot][y][w]);
                }
                dp1[tot][w^y][w]+=((LL)dp1[tot-1][w][w^y]*dp[v][y])%mod;
                chan(dp1[tot][w^y][w]);
            }
        }
    }
    dp[u][0]-=dp1[tot][1][0];
    if(dp[u][0]<0) dp[u][0]+=mod;
    dp[u][1]-=dp1[tot][0][0]+1;
    if(dp[u][1]<0) dp[u][1]+=mod;
}
int main()
{
    int n;
    cin>>n;
    for(int i=2;i<=n;i++){
        int p;
        scanf("%d",&p);
        g[p].push_back(i);
    }
    for(int i=1;i<=n;i++) sort(g[i].begin(),g[i].end());
    dfs(1);
    cout<<((dp[1][0]+dp[1][1])%mod+mod)%mod<<endl;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值