1. 程式人生 > 實用技巧 >BZOJ-4766 文藝計算姬(Prufer序列)

BZOJ-4766 文藝計算姬(Prufer序列)

題目描述

  給定一個一邊點數為 \(n\),另一邊點數為 \(m\),共有 \(n\times m\) 條邊的帶標號完全二分圖 \(K_{n,m}\),計算其生成樹個數(\(1\leq n,m\leq 10^{18}\))。

分析

  在 \(\text{Prufer}\) 序列的構建過程中,最後剩下兩個未被刪除的點之間一定有邊,因此這兩個點屬於二分圖的兩個不同集合,除了這兩個點之外,每個點都被刪除了一次。在刪除時,與被刪除點連邊的點會加入到 \(\text{Prufer}\) 序列中,根據二分圖的性質,左部點被加入到 \(\text{Prufer}\) 序列中 \(m-1\) 次,右部點被加入到 $ \text{Prufer}$ 序列中 \(n-1\)

次,即序列中有 \(n-1\) 個右部點和 \(m-1\) 個左部點,則生成樹個數為 \(n^{m-1}·m^{n-1}\)

程式碼

#include<bits/stdc++.h>
using namespace std;
long long n,m,mod;
long long quick_mul(long long a,long long b)
{
    long long ans=0;
    while(b)
    {
        if(b&1)
            ans=(ans+a)%mod;
        a=(a+a)%mod;
        b>>=1;
    }
    return ans%mod;
}
long long quick_pow(long long a,long long b)
{
    long long ans=1;
    while(b)
    {
        if(b&1)
            ans=quick_mul(ans,a)%mod;
        a=quick_mul(a,a)%mod;
        b>>=1;
    }
    return ans;
}
int main()
{
    cin>>n>>m>>mod;
    cout<<quick_mul(quick_pow(n,m-1),quick_pow(m,n-1))%mod<<endl;
    return 0;
}