【NOIP提高组】最近公共祖先

Description

YJC最近在学习树的有关知识。今天,他遇到了这么一个概念:最近公共祖先。对于有根树T的两个结点u、v,最近公共祖先LCA(T,u,v)表示一个结点x,满足x是u、v的祖先且x的深度尽可能大。YJC很聪明,他很快就学会了如何求最近公共祖先。他现在想寻找最近公共祖先有什么性质,于是他提出了这样的一个问题:n层的满k叉树T,求对于每一对(i,j)(1≤i,j≤T的点数),LCA(T,i,j)的深度的和是多少。这个数字n层的满k叉树指一棵带标号的有根树,深度为i(0≤i

Solution

比赛的时候其实没有想到一个比较好的递推式,自己推了个诡异的递推式,但是发现当答案小于模数时是对的,超过了模了之后就错掉了。
正解其实吼简单,优化O(n)的式子。O(n)很明显可以用所有点对减去不合法点对 n1i=0i(k2ni1ki)k1 ,通过若干步复杂的简化过后,它就成为了 k2nk(2n1)kn(k1) (不要问我怎么弄出来的,要用到等比数列公式),次幂直接快速幂解决就行了。

Code

const mo=998244353;
var
    n:longint;
    k,ans,ni:int64;
function ksm(x,y:int64):int64;
begin
    if y=0 then exit(1);
    if y mod 2=1 then ksm:=x*ksm(x,y-1) mod mo else ksm:=sqr(ksm(x,y div 2)) mod mo;
    exit(ksm);
end;
begin
    readln(n,k);
    ni:=(k-1)*(k-1) mod mo*(k-1) mod mo;
    ni:=ksm(ni,mo-2);
    ans:=ksm(k,2*n)-k;
    ans:=(ans-((2*n-1)*ksm(k,n))mod mo*(k-1))mod mo;
    ans:=ans*ni mod mo;
    while ans<0 do ans:=ans+mo;
    writeln(ans);
end.

你可能感兴趣的:(NOIP,DP,快速幂,树)