zoukankan      html  css  js  c++  java
  • Jzoj4888 最近公共祖先

    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<n)的点有k^i个,所有深度≠n-1的点都有k个孩子。YJC发现他不会做了,于是他来问你这个问题的答案。这个答案可能很大,你只需要告诉他答案%998244353的值就可以了。

    ​对于30%的数据,满足2≤n,k≤8;
    对于50%的数据,满足2≤n,k≤1000000;
    对于100%的数据,满足2≤n,k≤998244351。

    显然不是叫你写lca吧。。。

    对于每个节点我们考虑他的所有子节点能构成多少对

    选取一个节点x,设其所在子树大小为size

    一个节点s能和不在同一个子树内的所有节点匹配,所以就有size*(k-1)/k种选择方法

    所以x的贡献=deep[x]*size*size*(k-1)/2k

    但是这样不够快,我们需要得到O(lg N)的做法

    推导出(k-1)Answer=Σi*(k^(2n-i-1)-k^i){i∈[0,n)}

    继续利用 Σi*k^i {i∈[0,n)}=n*Σk^i - ΣΣk^j {j∈[0,i)} 和等比数列求和公式

    我们得到

    Answer=k^2n-k-(2n-1)*k^n*(k-1)/(k-1)^3

    可以用快速幂+逆元求解

    完成(这就是一道数学计算题嘛

    #include<stdio.h>
    #define M 998244353
    #define L long long
    L pow(L x,int k){
    	L S=1;
    	for(;k;x=x*x%M,k>>=1)
    		if(k&1) S=S*x%M;
    	return S;
    }
    int main(){
    	freopen("lca.in","r",stdin);
    	freopen("lca.out","w",stdout);
    	L n,k,S; scanf("%lld%lld",&n,&k);
    	S=pow(k,n*2);
    	S=(S-k-(2*n-1)*pow(k,n)%M*(k-1)%M+M+M)%M;
    	L inv=pow(k-1,M-2);
    	S=S*inv%M*inv%M*inv%M;
    	printf("%lld
    ",S);
    }


  • 相关阅读:
    Balanced Binary Tree
    Swap Nodes in Pairs
    Reverse Nodes in k-Group
    Reverse Linked List II
    Remove Nth Node From End of List
    Remove Duplicates from Sorted List II
    Remove Duplicates from Sorted List
    Partition List
    Merge Two Sorted Lists
    【Yii2.0】1.2 Apache检查配置文件语法
  • 原文地址:https://www.cnblogs.com/Extended-Ash/p/9477257.html
Copyright © 2011-2022 走看看