Problem A. 最近公共祖先 (commonants.c/cpp/pas)

注意

Input file: commonants.in

Output file: commonants.out

Time Limit : 0.5 seconds

Memory Limit: 512 megabytes

题面

最近公共祖先\(\text{(Lowest Common Ancestor,LCA)}\)是指在一个树中同时拥有给定的两个点作为后

代的最深的节点。

为了学习最近公共祖先,你得到了一个层数为\(n+1\)的满二叉树,其中根节点的深度为\(0\),其他节点的深度为父节点的深度\(+1\)。你需要求出二叉树上所有点对 \(\texttt{(i,j)}\),(\(i\),\(j\)可以相等,也可以\(i > j\))的最近公共祖先的深度之和对\(10^9+7\)取模后的结果。

输入格式

一行一个整数\(n\)。

输出格式

一行一个整数表示所有点对 \(\texttt{(i,j)}\),(\(i\),\(j\)可以相等,也可以\(i > j\))的最近公共祖先的深度之和对\(10^9+7\)取模后的结果。

样例

\(\texttt{input\#1}\)

2

\(\texttt{input\#2}\)

19260817

\(\texttt{output\#1}\)

22

\(\texttt{output\#2}\)

108973412

数据范围与提示

样例\(1\)解释:

树一共有\(7\)个节点(一个根节点和两个子节点),其中 \(\texttt{(4,4),(5,5),(6,6),(7,7)}\) 共\(4\)对的最近公共祖先深度为\(2\),\(\texttt{(4,2),(2,4),(5,2),(2,5),(5,4),(4,5),(2,2),(6,3),(3,6),(3,7),(7,3),(6,7),}\)\(\texttt{(7,6),(3,3)}\)共\(14\)对最近公共祖先深度是\(1\),其他的点对最近公共祖先深度为\(0\),所以答案为\(22\)。

对于\(20%\)的数据,\(n \le 10\)。

对于\(50%\)的数据,\(n \le 10^6\) 。

对于\(100%\)的数据,\(1 \le n \le 10^9\) 。


题解

对于一颗有\(n\)层的满二叉树很显然符合以下几点

1.第\(i\)层的点的个数为\(2^i\)。

2.以第\(i\)层的点为根节点的子树大小为\(2^{n-i+1}-1\)。

3.以第\(i\)层的点为\(\text{LCA}\)的点对个数为\(2^{2n-i+1}-2^i\)



观察上面的图(好丑),很明显\(1,2\)都是对的。

对于一颗以第\(i\)层的节点为根的子树:

①它的左子树与右子树上的点的\(\text{LCA}\)都为根节点。所以点对个数为

\[\LARGE\frac{2^{n-i+1}-2}{2} \times \frac{2^{n-i+1}-2}{2}
\]

\[\LARGE= (2^{n-i}-1) \times (2^{n-i}-1)
\]

\[\LARGE= 2^{2n-2i}-2^{n-i+1}+1
\]

②这棵子树的左子树与根节点的\(\text{LCA}\)都为根节点。右子树也是。所以有\(2^{n-i+1}-2\)对点。

③根节点与根节点的\(\text{LCA}\)也是根节点,点对个数为1。

点对\(\texttt{(u,v)}\)与点对\(\texttt{(v,u)}\)在\(u \neq v\)时是两个不同的点对。

所以将上述①②相加乘二再加③就是以子树根节点为\(\text{LCA}\)的点对的数量为:

\[\LARGE 2^{2n-2i+1}-1
\]

因为第\(i\)层的点的个数为\(2^i\)。所以以第\(i\)层的点为\(\text{LCA}\)的点对个数为:

\[\LARGE 2^{2n-i+1}-2^i
\]

因为一共有\(n+1\)层,从\(0-n\)层,所以答案为:

\[\LARGE \sum_{i=0}^{n} (2^{2n-i+1}-2^i) \times i
\]

\[\LARGE =\sum_{i=0}^{n} i \times 2^{2n-i+1}-i \times 2^i
\]

但这样复杂度为\(\Theta (nlog_n)\)过不了。。将上面的式子展开:

\[\LARGE \sum_{i=0}^{n} i \times 2^{2n-i+1} - \sum_{i=0}^{n} i \times 2^i
\]

\[\LARGE T_n=\sum_{i=0}^{n} i \times 2^{2n-i+1}
\]

\[\LARGE =2^{2n} + 2 \times 2^{2n-1} + 3 \times 2^{2n-2}+...+n \times 2^{n+1}
\]

\[\LARGE 2T_n=2^{2n+1} + 2 \times 2^{2n} + 3 \times 2^{2n-1}+...+n \times 2^{n+2}
\]

\[\Large 2T_n-T_n=2^{2n+1} + 2^{2n} + 2^{2n-1}+...+2^{n+2} - n \times 2^{n+1}
\]

\[\LARGE T_n=2^{2n+1} + 2^{2n} + 2^{2n-1}+...+2^{n+2} - n \times 2^{n+1}
\]

很明显前\(n\)项为等比数列,利用等比数列求和公式可以很快求出。

\[\LARGE T_n=\sum_{i=0}^{n} i \times 2^i
\]

\[\LARGE =2 + 2 \times 2^2 + 3 \times 2^3 +...+ n \times 2^n
\]

\[\LARGE 2T_n=2^2 + 2 \times 2^3 + 3 \times 2^4 + ... + n \times 2^{n+1}
\]

\[\LARGE T_n-2T_n=2 + 2^2 + 2^3 +...+2^n- n \times 2^{n+1}
\]

很明显也是等比数列。将这两个相加就是答案了。

快速幂是\(log\)。所以复杂度是\(\Theta(log_n)\)


\(Code\)

#include<bits/stdc++.h>
typedef long long ll;
ll n;
const ll mod=1000000007; inline void read(ll &T) {
ll x=0;bool f=0;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=!f;c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
T=f?-x:x;
} inline ll qpow(ll a,ll b) {
ll ans=1,base=a;
while(b) {
if(b&1) ans=(ans*base)%mod;
base=(base*base)%mod;
b>>=1;
}
return ans%mod;
} int main() {
read(n);
ll qwq=(((2*qpow(2,2*n+1))%mod-qpow(2,n+2)+5*mod)%mod-n*qpow(2,n+1)+5*mod)%mod;
ll qaq=((((2*qpow(2,n))%mod)-2+5*mod)%mod-n*qpow(2,n+1)+5*mod)%mod;
//std::cout<<qwq<<'\n'<<qaq<<'\n';
std::cout<<(qwq+qaq+5*mod)%mod;//加上一个模数再取模是为了处理负数的情况
return 0;
}

【CSP-S膜你考】最近公共祖先 (数学)的更多相关文章

  1. 【CSP-S膜你考】即时战略(模拟)

    Problem B. 即时战略 (rts.c/cpp/pas) 注意 Input file: rts.in Output file: rts.out Time Limit : 2 seconds Me ...

  2. 8.3考试总结(NOIP模拟19)[最长不下降子序列·完全背包问题·最近公共祖先]

    一定要保护自己的梦想,即使牺牲一切. 前言 把人给考没了... 看出来 T1 是一个周期性的东西了,先是打了一个暴力,想着打完 T2 T3 暴力就回来打.. 然后,就看着 T2 上头了,后来发现是看错 ...

  3. poj 1330 Nearest Common Ancestors(LCA:最近公共祖先)

    多校第七场考了一道lca,那么就挑一道水题学习一下吧= = 最简单暴力的方法:建好树后,输入询问的点u,v,先把u全部的祖先标记掉,然后沿着v->rt(根)的顺序检查,第一个被u标记的点即为u, ...

  4. Solution: 最近公共祖先·一 [hiho一下 第十三周]

    题目1 : 最近公共祖先·一 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 小Ho最近发现了一个神奇的网站!虽然还不够像58同城那样神奇,但这个网站仍然让小Ho乐在其中 ...

  5. 「LuoguP3379」 【模板】最近公共祖先(LCA)

    题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每 ...

  6. [知识点]最近公共祖先LCA

    UPDATE(20180822):重写部分代码. 1.前言 最近公共祖先(LCA),作为树上问题,应用非常广泛,而求解的方式也非常多,复杂度各有不同,这里对几种常用的方法汇一下总. 2.基本概念和暴力 ...

  7. LCA最近公共祖先 ST+RMQ在线算法

    对于一类题目,是一棵树或者森林,有多次查询,求2点间的距离,可以用LCA来解决.     这一类的问题有2中解决方法.第一种就是tarjan的离线算法,还有一中是基于ST算法的在线算法.复杂度都是O( ...

  8. 【转】最近公共祖先(LCA)

    基本概念 LCA:树上的最近公共祖先,对于有根树T的两个结点u.v,最近公共祖先LCA(T,u,v)表示一个结点x,满足x是u.v的祖先且x的深度尽可能大. RMQ:区间最小值查询问题.对于长度为n的 ...

  9. 【并查集】【树】最近公共祖先LCA-Tarjan算法

    最近公共祖先LCA 双链BT 如果每个结点都有一个指针指向它的父结点,于是我们可以从任何一个结点出发,得到一个到达树根结点的单向链表.因此这个问题转换为两个单向链表的第一个公共结点(先分别遍历两个链表 ...

随机推荐

  1. 用这个模型去理解CPU?

  2. Python基础6

    <零基础入门学习python>,小甲鱼. P33. 用for循环和range() 配合求数列和,对比while循环,简洁很多

  3. S5PV210 固件烧写 u-boot烧写

    首先阅读CW210_CD自带光盘中CW210 开发板使用手册.pdf 使用usb 拨码开关置成usb启动.xx可以是ON或OFF.开发板上面也有丝印提示 usb线接好,串口线接好 使用DNW下载 自带 ...

  4. mybatis 批量添加数据的两种实现方式

    做开发的这几年期间经常遇到类似处理这种形式数据的问题,也遇到很多刚刚入行的新同学,发现他们做处理这块,经验不够,今天特地整理了一下,大家都会遇到的几种情况,代码也都粘贴出来了,拿去不谢,有时间大家还是 ...

  5. 几种线程相关的map介绍

    Java中平时用的最多的Map集合就是HashMap了,它是线程不安全的. 看下面两个场景: 1.当用在方法内的局部变量时,局部变量属于当前线程级别的变量,其他线程访问不了,所以这时也不存在线程安全不 ...

  6. Pandas 之 DataFrame 常用操作

    import numpy as np import pandas as pd This section will walk you(引导你) through the fundamental(基本的) ...

  7. GitPython模块

    GitPython模块 安装: pip3 install gitpython Gitpython 操作 import os from git.repo import Repo import json ...

  8. jieba分词及词频统计小项目

    import pandas as pd import jieba import jieba.analyse from collections import Counter,OrderedDict ji ...

  9. Spark 安装教程

    Spark 安装教程 本文原始地址:https://sitoi.cn/posts/45358.html 安装环境 Fedora 29 openjdk version "1.8.0_191&q ...

  10. (二)Kubernetes kubeadm部署k8s集群

    kubeadm介绍 kubeadm是Kubernetes项目自带的及集群构建工具,负责执行构建一个最小化的可用集群以及将其启动等的必要基本步骤,kubeadm是Kubernetes集群全生命周期的管理 ...