BZOJ 4766 文艺计算姬 Prufer序列

来源:互联网 发布:潘多网络是做什么的 编辑:程序博客网 时间:2024/04/30 06:21

题目大意:给定一个一边点数为n,另一边点数为m,共有n*m条边的带标号完全二分图K_{n,m},计算其生成树个数。
1 <= n,m,p <= 1e18

因为prufer序列对应着唯一的一棵树,问题转为计算有多少合法的prufer序列。
“一种生成Prufer序列的方法是迭代删点,直到原图仅剩两个点。”根据prufer序列的性质,最后剩下的两个点一定有一条边,在二分图中有连边的两点一定处于不同集合。在删除时会“移去所有叶子节点(度为1的顶点)中标号最小的顶点和相连的边,并把与它相邻的点的编号加入Prufer序列中”,每删除一个点都需要将与它连边的点加到prufer序列中,而二分图中的边两端的点一定属于不同集合,那么A集合有n-1个点被删除,也就是说B集合中的数需要被加入n-1次,共有mn1种可能;B集合同理,有m-1个点被删除,也就是说A集合中的数需要被加入m-1次,共有nm1种可能。
两种情况相乘得到答案为nm1mn1

这道题我本来想偷懒用python但是它太慢了直接T爆

#include <cstdio>using namespace std;typedef long long LL;LL n,m,MOD;LL f_times(LL x,LL y) {    LL tmp=0;    while(y) {        if(y&1) tmp=(tmp+x)%MOD;        x=(x+x)%MOD;        y>>=1;    }    return tmp;}LL f_pow(LL x,LL y) {    LL tmp=1;    while(y) {        if(y&1) tmp=f_times(tmp,x);        x=f_times(x,x);        y>>=1;    }    return tmp;}int main() {    scanf("%lld%lld%lld",&n,&m,&MOD);    printf("%lld\n",f_times(f_pow(n,m-1),f_pow(m,n-1)));    return 0;}
n,m,mod=map(int,raw_input().split())print((n**(m-1))*(m**(n-1))%mod)
原创粉丝点击