Bracket Sequences on Tree【哈希+随机数+树DP】

题目链接 HDU-6647


  有一棵N个点构成的无根树,我们可以任选一点开始进行dfs跑,得到一个括号序,现在我们想知道跑完整个dfs,有多少种括号序?

  于是,可以比较容易的想到,我们可以推一个dp方程来解出从一个点出发,得到的方案数,假设dp[u]表示以u为子树的根节点时候的跑完下面子树的种类数,那么可以看到dp[u] = \frac{(degree[u] !)}{\prod a_i!} \cdot \prod dp[v],其中,a_i表示u的不同形态的子树的个数。

  于是,我们可以根据这个式子来进行DP得到目前假设的根节点的值,然后再根据该式子可以进行换根DP得到剩下以每个点为根时候的答案值,当然,当以它为根时候的树跟其他点为根的树是同构的时候,这时只需要算一个的答案就可以了。

  然后,这里的哈希值,我选用了随机数,因为一开始被卡了。

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
#define pii pair
#define MP(a, b) make_pair(a, b)
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
vector Prime;
bool not_Prime[1300007] = {false};
void Prime_Init()
{
    for(int i=2; Prime.size() <= 100000 && i<1300000; i++)
    {
        if(!not_Prime[i])
        {
            Prime.push_back(i);
            for(int j = i * 2; j < 1300000; j += i) not_Prime[j] = true;
        }
    }
}
const ll mod = 998244353;
const int maxN = 1e5 + 7;
inline void MOD(ll &x) { x = x >= mod ? x % mod : x; }
inline ll mul(ll a, ll b) { a *= b; MOD(a); return a; }
inline ll qpow(ll a, ll b = mod - 2)
{
    ll ans = 1;
    while(b)
    {
        if(b & 1) ans = mul(ans, a);
        b >>= 1;
        a = mul(a, a);
    }
    return ans;
}
ll jc[maxN], inv_jc[maxN];
int N;
namespace Graph
{
    int head[maxN], cnt;
    struct Eddge
    {
        int nex, to;
        Eddge(int a=-1, int b=0):nex(a), to(b) {}
    } edge[maxN << 1];
    inline void addEddge(int u, int v)
    {
        edge[cnt] = Eddge(head[u], v);
        head[u] = cnt++;
    }
    inline void _add(int u, int v) { addEddge(u, v); addEddge(v, u); }
    inline void init()
    {
        cnt = 0;
        for(int i=1; i<=N; i++) head[i] = -1;
    }
};
using namespace Graph;
unordered_map mp[maxN];
unordered_map::iterator it;
unordered_map root_Tree;
uit siz[maxN], du[maxN];
ll dp[maxN], ans;
ull f[maxN];
void dfs(int u, int fa)
{
    siz[u] = 1;
    f[u] = 1;
    int num = 0;
    ll pi_dp_v = 1;
    for(int i=head[u], v; ~i; i=edge[i].nex)
    {
        v = edge[i].to;
        if(v == fa) continue;
        dfs(v, u);
        num++;
        f[u] += f[v] * Prime[siz[v]];
        siz[u] += siz[v];
        mp[u][f[v]]++;
        pi_dp_v = mul(pi_dp_v, dp[v]);
    }
    du[u] = num;
    dp[u] = mul(jc[num], pi_dp_v);
    for(it = mp[u].begin(); it != mp[u].end(); it++)
    {
        dp[u] = mul(dp[u], inv_jc[it->second]);
    }
}
void ex_dfs(int u, int fa, ull fa_f, ll fa_dp)
{
    ull now_f = f[u] + fa_f * Prime[N - siz[u]];
    ll now_dp = dp[u];
    now_dp = mul(now_dp, fa_dp);
    now_dp = mul(now_dp, mul(inv_jc[du[u]], jc[du[u] + 1]));
    now_dp = mul(now_dp, mul(jc[mp[u][fa_f]], inv_jc[mp[u][fa_f] + 1]));
    mp[u][fa_f]++;
    du[u]++;
    if(!root_Tree[now_f])
    {
        root_Tree[now_f] = true;
        ans += now_dp;
        MOD(ans);
    }
    ull nex_f; ll nex_dp;
    for(int i=head[u], v; ~i; i=edge[i].nex)
    {
        v = edge[i].to;
        if(v == fa) continue;
        nex_f = now_f - f[v] * Prime[siz[v]];
        nex_dp = mul(now_dp, qpow(dp[v]));
        nex_dp = mul(nex_dp, mul(inv_jc[du[u]], jc[du[u] - 1]));
        nex_dp = mul(nex_dp, mul(jc[mp[u][f[v]]], inv_jc[mp[u][f[v]] - 1]));
        ex_dfs(v, u, nex_f, nex_dp);
    }
}
inline void pre_Do()
{
    Prime_Init();
    for(int i=1, l, r; i<=100000; i++)
    {
        l = rand() % 100000 + 1; r = rand() % 100000 + 1;
        swap(Prime[l], Prime[r]);
    }
    jc[0] = 1;
    for(ll i = 1; i < maxN; i++) jc[i] = mul(i, jc[i - 1]);
    inv_jc[maxN - 1] = qpow(jc[maxN - 1]);
    for(int i = maxN - 2; i >= 0; i--) inv_jc[i] = mul(inv_jc[i + 1], i + 1);
}
int main()
{
    pre_Do();
    int T; scanf("%d", &T);
    while(T--)
    {
        scanf("%d", &N);
        root_Tree.clear();
        for(int i=1; i<=N; i++) mp[i].clear();
        init();
        for(int i=1, u, v; i

 

你可能感兴趣的:(哈希,DP动态规划,哈希,树DP,换根)