2018.10.15【BZOJ4766】文艺计算姬(矩阵快速幂)(矩阵树)(prufer序列)(结论题)

传送门


解析:

显然可以用 M a t r i x − T r e e Matrix-Tree MatrixTree来做 推导。

思路:

我们直接建出基尔霍夫矩阵 H H H,显然我们可以把它分成四块:
左上角为 A A A是一个 n × n n\times n n×n的对角线为 m m m的矩阵,其余为0。
右上角为 B B B是一个 n × ( m − 1 ) n\times (m-1) n×(m1)的全部为 − 1 -1 1的矩阵
左下角为 C C C是一个 ( m − 1 ) × n (m-1)\times n (m1)×n的全部为 − 1 -1 1的矩阵,即矩阵 B B B的转置
右下角为 D D D是一个 ( m − 1 ) × ( m − 1 ) (m-1)\times (m-1) (m1)×(m1)的对角线为 n n n的矩阵,其余为0。

把矩阵推导一下: ∣ H ∣ = ∣ A ∣ × ∣ D − C × A − 1 × B ∣ |H|=|A|\times |D-C\times A^{-1}\times B| H=A×DC×A1×B

那么 ∣ A ∣ |A| A就显然是 n m n^m nm

后面的再推一下。

A − 1 A^{-1} A1 A A A的逆,规模相同,对角线为 1 / m 1/m 1/m

那么这一坨就可以推出了: C × A − 1 × B C\times A^{-1}\times B C×A1×B是一个规模为 ( m − 1 ) × ( m − 1 ) (m-1)\times(m-1) (m1)×(m1),所有元素为 n / m n/m n/m的矩阵。

后面一大坨就直接作差得到一个矩阵 T T T T T T的对角线上全部是 n − n / m n-n/m nn/m,其余部分是 − n / m -n/m n/m,规模为 ( m − 1 ) × ( m − 1 ) (m-1)\times (m-1) (m1)×(m1)

我们直接把 n / m n/m n/m提出来得到新的矩阵 T ′ T' T T ′ T' T的对角线就全部都是 m − 1 m-1 m1,其余部分全部都是 − 1 -1 1

这个 T ′ T' T。。。

好的这道题做完了。

这个 T ′ T' T对应的基尔霍夫矩阵求的就是有 m m m个节点的无向完全图的生成树个数 。由 p r u f e r prufer prufer序列瞎推一波可以知道生成树个数就是 m m − 2 m^{m-2} mm2

再把刚才提出来的 ( n / m ) m − 1 (n/m)^{m-1} (n/m)m1和原来的 ∣ A ∣ |A| A乘回去就可以知道我们要求的东西了 K n , m = ∣ H n , m ∣ = n m − 1 × m n − 1 K_{n,m}=|H_{n,m}|=n^{m-1}\times m^{n-1} Kn,m=Hn,m=nm1×mn1

trick:

直接乘肯定会爆 l o n g l o n g long long longlong,考场上又不可能用__int128。
所以去学习一下龟速乘吧。

当然还有 O ( 1 ) O(1) O(1)的龟速乘


代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const

inline ll getint(){
	re ll num;
	re char c;
	while(!isdigit(c=gc()));num=c^48;
	while(isdigit(c=gc()))num=(num<<1)+(num<<3)+(c^48);
	return num;
}

ll mod;

inline ll mul(ll a,ll b){
	return (a*b-(ll)((long double)a/mod*b)*mod+mod)%mod;
/*	ll ans=0;
	while(b){
		if(b&1)ans=(ans+a)%mod;
		a=(a+a)%mod;
		b>>=1;
	}
	return ans;*/
}

inline ll quickpow(ll a,ll b){
	ll ans=1;
	while(b){
		if(b&1)ans=mul(ans,a);
		a=mul(a,a);
		b>>=1;
	}
	return ans;
}

ll n,m;
signed main(){
	n=getint(),m=getint(),mod=getint();
	cout<<(ll)mul(quickpow(n,m-1),quickpow(m,n-1));
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值