【ZJOI2017 Round1练习&BZOJ4766】D1T2 文艺计算姬(Prufer编码)
题意:给定一个一边点数为n,另一边点数为m,共有n*m条边的带标号完全二分图K_{n,m},求其生成树个数 mod p。
100%的数据:1 <= n,m,p <= 10^18
思路:这是一道结论(打表找规律)+教你快速幂和乘法 题
结论为:S=n^(m-1)*m^(n-1)
需要注意的是n,m过大,普通的快速幂与乘法会炸
所以需要手写乘法,类似于快速幂的形式将其转换为加法
2017.2.28:%%%CC的证明:
设两边为X侧,Y侧
考虑它们在Prufer序列中出现的位置与取值种数
生成树的最后一条边一定链接一个X侧一个Y侧点
一个X侧点的插入就代表一个Y侧点被删除
因为最后只剩一个X侧点一个Y侧点
所以X侧点会出现M-1次,每次出现有N种取值,每个X侧点可以重复出现
所以对于X侧点有n^(m-1)种取值
Y侧点同理
得证
1 var n,m,mo:int64; 2 3 function clac(x,y:int64):int64; 4 begin 5 clac:=0; 6 while y>0 do 7 begin 8 if y and 1=1 then clac:=(clac+x) mod mo; 9 x:=(x+x) mod mo; 10 y:=y>>1; 11 end; 12 end; 13 14 function mult(x,y:int64):int64; 15 begin 16 mult:=1; 17 while y>0 do 18 begin 19 if y and 1=1 then mult:=clac(mult,x) mod mo; 20 x:=clac(x,x) mod mo; 21 y:=y>>1; 22 end; 23 end; 24 25 begin 26 assign(input,'art.in'); reset(input); 27 assign(output,'art.out'); rewrite(output); 28 readln(n,m,mo); 29 writeln(clac(mult(n,m-1),mult(m,n-1))); 30 close(input); 31 close(output); 32 end.
null