一开始的想法是枚举路径的 \(\rm LCA\) 然后再枚举两边的深度,但是这样无论如何我都只能做到 \(O(n ^ 3)\) 的复杂度。

只能考虑换一种方式计数,注意到点分治可以解决树上一类路径问题,于是我们考虑使用类似点分治的方式对树上路径计数。

具体地,我们考虑计算以 \(i\) 为端点的路径数量,那么就会存在两种路径:向上走的和向下走的,分别令其为 \(f, g\)。

因为深度相同的点都是等价的,因此我们将状态设置为: \(f_{i, j}\) 表示从 \(i\) 开始往上长度为 \(j\) 的路径数,对 \(g\) 类似。

那么你会发现 \(g\) 是非常好求的,因为往下走就只可能一直往儿子走,本质上就是往下走 \(j\) 层后的点的数量,那么可知:

\[g_{i, j} = \prod_{k = 1} ^ j a_{i + k - 1} = g_{i, j - 1} \times a_{i + j - 1}
\]

再来考虑如何求 \(f\),可以发现 \(i\) 往上走必然会经过 \(fa_i\),之后又分为两种情况:\(fa_i\) 往下走或 \(i\) 继续往上走 \(j - 1\) 步,那么有转移:

\[f_{i, j} = f_{i - 1, j - 1} + g_{i - 1, j - 1}
\]

但是需要减去 \(fa_i\) 往下走到 \(i\) 的方案数,即:

\[f_{i, j} = f_{i - 1, j - 1} + g_{i - 1, j - 1} - g_{i, j - 2}
\]

特别的,当 \(f_{i, 0}, g_{i, 0}\) 我们只能钦定一个为 \(1\),否则在计算 \(f_{i, 1}\) 时会记重,为了方便 \(g\) 的计算,我们令 \(g_{i, 0} = 1, f_{i, 0} = 0\)。

最终求答案的时候你会认为答案是 \(\sum\limits_{i = 1} ^ n a_i \times (f_{i, k} + g_{i, k})\),但是可以发现同一条路径会在两个端点处被计算一次,因此答案还需减半。

#include <bits/stdc++.h>
using namespace std;
#define rep(i, l, r) for (int i = l; i <= r; ++i)
const int N = 10000 + 5;
const int M = 5000 + 5;
const int Mod = 1e9 + 7;
int n, inv, cur, a[N], b[N], ans[N], f[2][N], g[M][M];
int read() {
char c; int x = 0, f = 1;
c = getchar();
while (c > '9' || c < '0') { if(c == '-') f = -1; c = getchar();}
while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x * f;
}
int Inc(int a, int b) { return (a += b) >= Mod ? a - Mod : a;}
int Dec(int a, int b) { return (a -= b) < 0 ? a + Mod : a;}
int Mul(int a, int b) { return 1ll * a * b % Mod;}
int fpow(int a, int b) { int ans = 1; for (; b; a = Mul(a, a), b >>= 1) if(b & 1) ans = Mul(ans, a); return ans;}
int main() {
n = read(), inv = fpow(2, Mod - 2);
b[1] = 1;
rep(i, 1, n - 1) a[i] = read(), b[i + 1] = Mul(b[i], a[i]);
rep(i, 1, n) {
g[i][0] = 1;
rep(j, 1, n - i) g[i][j] = Inc(g[i][j], Mul(g[i][j - 1], a[i + j - 1]));
}
f[0][0] = cur = 1;
rep(i, 2, n) {
rep(j, 1, 2 * n - 2) f[cur][j] = 0;
f[cur][0] = 1;
rep(j, 1, 2 * n - 2) {
f[cur][j] = Inc(f[cur][j], f[cur ^ 1][j - 1]);
if(j - 1 <= n && j - 1 > 0) f[cur][j] = Inc(f[cur][j], Dec(g[i - 1][j - 1], g[i][j - 2]));
}
rep(j, 1, 2 * n - 2) ans[j] = Inc(ans[j], Mul(Mul(Inc(f[cur][j], (j < i)), b[i]), inv));
cur ^= 1;
}
rep(i, 1, 2 * n - 2) printf("%d ", ans[i]);
return 0;
}

从本题当中可以看出书上路径计数的两种方法:

  1. 通过枚举 \(\rm LCA\),当要求的路径特征与端点无太多关系时常用。

  2. 通过枚举端点,然后运用类似点分治的方式递推,多用于点对之间有要求的问题,例如本题。

CF954H Path Counting的更多相关文章

  1. CF 954H Path Counting

    H. Path Counting time limit per test 5 seconds memory limit per test 256 megabytes input standard in ...

  2. Codeforces 954H Path Counting 【DP计数】*

    Codeforces 954H Path Counting LINK 题目大意:给你一棵n层的树,第i层的每个节点有a[i]个儿子节点,然后问你树上的简单路径中长度在1~n*2-2之间的每个有多少条 ...

  3. Codeforces 954H Path Counting(DP)

    题目链接  Path Counting 题意  给定一棵高度为$n$的树,给出每一层的每个点的儿子个数(某一层的所有点儿子个数相同).   令$f_{k}$为长度为$k$的路径条数,求$f_{1}, ...

  4. Educational Codeforces Round 40 (Rated for Div. 2) Solution

    从这里开始 小结 题目列表 Problem A Diagonal Walking Problem B String Typing Problem C Matrix Walk Problem D Fig ...

  5. Leetcode: Longest Absolute File Path

    Suppose we abstract our file system by a string in the following manner: The string "dir\n\tsub ...

  6. gogs仓库管理软件 exec: "git-upload-pack": executable file not found in $PATH

    当配置完个人中心的ssh公钥的时候,在客户端拉取代码的时候,提示如下错误: Cloning into 'comix-b2m'... Gogs: Internal error fatal: Could ...

  7. git推送报错: No path specified. See 'man git-pull' for valid url syntax或does not appear to be a git repository以及remote: error: insufficient permission for adding an object to repository databa

    本地(windows)代码想推送到linux自己搭建的git服务端,第一步是建立本地与服务端的关联,第二步是本地推送到服务端. 第一步需要看你的本地工程是否从git上clone来的,如果是clone来 ...

  8. NodeJs之Path

    Path模块 NodeJs提供的Path模块,使得我们可以对文件路径进行简单的操作. API var path = require('path'); var path_str = '\\Users\\ ...

  9. 【原】实时渲染中常用的几种Rendering Path

    [原]实时渲染中常用的几种Rendering Path 本文转载请注明出处 —— polobymulberry-博客园 本文为我的图形学大作业的论文部分,介绍了一些Rendering Path,比较简 ...

随机推荐

  1. Adversarial Examples Are Not Bugs, They Are Features

    目录 概 主要内容 符号说明及部分定义 可用特征 稳定可用特征 可用不稳定特征 标准(standard)训练 稳定(robust)训练 分离出稳定数据 分离出不稳定数据 随机选取 选取依赖于 比较重要 ...

  2. uniapp动态修改导航栏

    1.修改导航栏buttons 如图动态修改角标 <template> <view> </view> </template> <script> ...

  3. CS5210|低成本HDMI转VGA方案|CS5210参数说明

    Capstone最新推出的一款HDMI转VGA音视频转接线或者转换器方案芯片CS5210. 其设计的优势在于内置晶振,外围电路器件较少设计简单,芯片封装集成度较高,方案BOM成本低,相比其他方案产品更 ...

  4. Java+Eclipse+MySQL+Swing实现学生会考成绩管理系统(免费完整项目)

    版权声明:原创不易,本文禁止抄袭.转载,侵权必究! 目录 一.需求开发文档 二.数据库设计文档 三.功能模块部分代码及效果展示 四.完整源码下载 五.作者Info 一.需求开发文档 项目完整文件列表: ...

  5. 基于Spring MVC + Spring + MyBatis的【图书信息管理系统(一)】

    资源下载:https://download.csdn.net/download/weixin_44893902/34867237 练习点设计:模糊查询.删除.新增 一.语言和环境 1.实现语言:JAV ...

  6. 万能密码:‘or 1=1-- 实战SQL注入,秒破后台

    主要是没有对登录密码的字符串进行参数化和过滤,所以导致网站可以直接用"万能密码"进行突破登录 仅供学习交流 这是某同学做的网站,今天无聊打开了,并帮他进行测试一下 看到这个后台,感 ...

  7. MySQL创建数据库 easyShopping,包括area表、goods表、customer表、orders表、ordersdetall表、test表

    MySQL创建数据库 easyShopping,包括area表.goods表.customer表.orders表.ordersdetall表.test表 商品表表结构: 字段名 说 明 类 型 长 度 ...

  8. 初识python: 继承实例 - 学校、老师、学生

    对学校.老师.学生做一个分类,并抽象成类.并实现各自的一些功能.代码如下: 父类1:学校 # 学校 class School(object): def __init__(self,name,addr) ...

  9. 360浏览器兼容模式下jsp页面访问不到js文件

    360浏览器兼容模式下jsp页面访问不到js文件 查看自己js中的语法问题,不要用ES6的语法,编译不了故找不到js文件 const var of 码出高效 java 比较 所有整型包装类对象之间值的 ...

  10. day3 创建数组并完成对数组的操作

    1.实现函数action()初始化数据全0的操作 2.实现函数assignment()利用指针给数组赋值0~9 3.实现函数print()打印数组的每个函数 4.实现函数reverse()完成对数组的 ...