Topcoder SRM 683 Div2

树形Dp的题,根据题意建树。

DP[i][0] 表示以i为根节点的树的包含i的时候的所有状态点数的总和

Dp[i][1] 表示包含i结点的状态数目

对于一个子节点v

Dp[i][0] = (Dp[v][1]+1)*Dp[i][0]+Dp[v][0]*Dp[i][1]

表示子节点的所有状态与i的所有的状态之间的组合(可以不组合,所以DP[v][1]+1),

接下来更新i的状态数目

DP[i][1] = Dp[i][1]*(Dp[v][1]+1)

这样就可以算出来i结点为根结的所以状态,树中的所有点的状态和就是答案。

#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <ctime>

using namespace std;

typedef long long LL;

typedef vector<int>VI;

const int Max = 1e5+10;

const LL Mod = 1e9+7;


LL  Dp[Max][2];

LL a[Max];

VI M[Max];

void DFS(int u, int fa)
{
    Dp[u][0] = Dp[u][1] = 1;

    for(int i = 0;i < M[u].size(); i++)
    {   
        if(M[u][i] == fa) continue;

        DFS(M[u][i], u);

        int v = M[u][i];

        Dp[u][0] = (((Dp[v][1] + 1) * Dp[u][0]) % Mod + (Dp[u][1] * Dp[v][0]) % Mod) % Mod;

        Dp[u][1] = (Dp[u][1] * (Dp[v][1]+1)) % Mod;
    }
}

class SubtreesCounting {
public:
    int sumOfSizes(int, int, int, int, int);
};

int SubtreesCounting::sumOfSizes(int n, int a0, int b, int c, int m) 
{
    a[0] = a0;

    for(int i = 1;i <= n-1; i++)
    {
        a[i] = (b * a[i-1] + c) % m;
    }

    for(int i = 1 ;i <= n-1; i++)
    {
        int j = a[i-1] % i;

        M[i].push_back(j);

        M[j].push_back(i);
    }


    LL ans = 0;

    for(int  i = 0; i < n; i++)
    {
        if(!Dp[i][0]) DFS(i,-1);

        ans = (ans + Dp[i][0]) % Mod;
    }

    return ans;
}
原文地址:https://www.cnblogs.com/juechen/p/5255856.html