【bzoj2159】Crash 的文明世界(树形dp+第二类斯特林数)
题意:
给出一颗\(n\)个结点的树,对于每个结点输出其答案,每个结点的答案为\(ans_x=\sum_{i=1}^ndis(x,i)^k\)。
思路:
我们对于每个结点将其答案展开:
ans_x=&\sum_{i=0}^{n}\sum_{j=0}^k{dis(x,i)\choose j}j!\begin{Bmatrix}
k \\ j
\end{Bmatrix}\\
=&\sum_{j=0}^kj!\begin{Bmatrix}
k \\ j
\end{Bmatrix}\sum_{i=0}^n{dis(x,i)\choose j}
\end{aligned}
\]
现在就考虑如何快速求\(\displaystyle \sum_{i=0}^n{dis(x,i)\choose j}\)。
因为组合数可以展开,所以我们可以写成:
\]
如果\(x\)为根节点的话,那么答案很好求,我们只需要对每个点求出其子树的答案。我们记\(f[i][j]\)为以\(i\)为根的子树中,\(\displaystyle \sum_{k=0}^n{dis(k,i)\choose j}\)的答案。那么每个结点更新答案时由其儿子结点转移过来即可。
最后再换下根即可求出以所有结点为根结点的答案,当\(u\)向\(v\)转移时,要减去\(v\)结点的贡献才能得出以\(u\)为根节点的子树的值。
细节见代码:
/*
 * Author:  heyuhhh
 * Created Time:  2019/12/14 14:56:05
 */
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cstdio>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <iomanip>
#define MP make_pair
#define fi first
#define se second
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
#define Local
#ifdef Local
  #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
  void err() { std::cout << '\n'; }
  template<typename T, typename...Args>
  void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
#else
  #define dbg(...)
#endif
void pt() {std::cout << '\n'; }
template<typename T, typename...Args>
void pt(T a, Args...args) {std::cout << a << ' '; pt(args...); }
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 5e4 + 5, M = 155, MOD = 10007;
int n, k;
int f[N][M], g[N][M];
vector <int> G[N];
int s[M][M], fac[M], inv[M];
ll qpow(ll a, ll b) {
    ll ans = 1;
    while(b) {
        if(b & 1) ans = ans * a % MOD;
        a = a * a % MOD;
        b >>= 1;
    }
    return ans;
}
void init() {
    s[0][0] = 1;
    for(int i = 1; i < M; i++)
        for(int j = 1; j <= i; j++)
            s[i][j] = (s[i - 1][j] * j + s[i - 1][j - 1]) % MOD;
    fac[0] = 1;
    for(int i = 1; i < M; i++) fac[i] = 1ll * fac[i - 1] * i % MOD;
    inv[M - 1] = qpow(fac[M - 1], MOD - 2);
    for(int i = M - 2; i >= 0; i--) inv[i] = 1ll * inv[i + 1] * (i + 1) % MOD;
}
void dfs(int u, int fa) {
    f[u][0] = 1;
    for(int j = 0; j < sz(G[u]); j++) {
        int v = G[u][j];
        if(v != fa) {
            dfs(v, u);
            for(int i = 0; i <= k; i++) {
                f[u][i] = (f[u][i] + f[v][i]) % MOD;
                if(i) f[u][i] = (f[u][i] + f[v][i - 1]) % MOD;
            }
        }
    }
}
void dfs2(int u, int fa) {
    for(int j = 0; j < sz(G[u]); j++) {
        int v = G[u][j];
        if(v != fa) {
            for(int i = 0; i <= k; i++) {
                g[v][i] = (g[v][i] + g[u][i] - f[v][i] + MOD) % MOD;
                if(i) g[v][i] = (g[v][i] + g[u][i - 1] - f[v][i - 1] + MOD - f[v][i - 1] + MOD) % MOD;
                if(i > 1) g[v][i] = (g[v][i] - f[v][i - 2] + MOD) % MOD;
            }
            dfs2(v, u);
        }
    }
}
void run(){
    //cin >> n >> k;
    //for(int i = 1; i < n; i++) {
        //int u, v; cin >> u >> v;
        //G[u].push_back(v);
        //G[v].push_back(u);
    //}
    int L,now,A,B,Q;
    cin >> n >> k >> L >> now >> A >> B >> Q;
    for(int i = 1; i < n; i++) {
        now = (now * A + B) % Q;
        int tmp = i < L ? i : L;
        int x = i - now % tmp, y = i + 1;
        G[x].push_back(y);
        G[y].push_back(x);
    }
    dfs(1, 0);
    for(int i = 1; i <= n; i++)
        for(int j = 0; j <= k; j++)
            g[i][j] = f[i][j];
    dfs2(1, 0);
    for(int i = 1; i <= n; i++) {
        int ans = 0;
        for(int j = 0; j <= k; j++) {
            ans = (ans + 1ll * fac[j] * s[k][j] * g[i][j]) % MOD;
        }
        printf("%d\n", ans);
    }
}
int main() {
    init(); run();
    return 0;
}
【bzoj2159】Crash 的文明世界(树形dp+第二类斯特林数)的更多相关文章
- BZOJ2159 Crash的文明世界——树上DP&&第二类Stirling数
		题意 给定一个有 $n$ 个结点的树,设 $S(i)$ 为第 $i$ 个结点的“指标值”,定义为 $S(i)=\sum_{i=1}^{n}dist(i,j)^k$,$dist(i, j)$ 为结点 $ ... 
- BZOJ 2159: Crash 的文明世界(树形dp+第二类斯特林数+组合数)
		题意 给定一棵 \(n\) 个点的树和一个常数 \(k\) , 对于每个 \(i\) , 求 \[\displaystyle S(i) = \sum _{j=1} ^ {n} \mathrm{dist ... 
- 【hdu4045】Machine scheduling(dp+第二类斯特林数)
		传送门 题意: 从\(n\)个人中选\(r\)个出来,但每两个人的标号不能少于\(k\). 再将\(r\)个人分为不超过\(m\)个集合. 问有多少种方案. 思路: 直接\(dp\)预处理出从\(n\ ... 
- bzoj 2159 Crash 的文明世界 && hdu 4625 JZPTREE ——第二类斯特林数+树形DP
		题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2159 学习材料:https://blog.csdn.net/litble/article/d ... 
- P4827 [国家集训队] Crash 的文明世界(第二类斯特林数+树形dp)
		传送门 对于点\(u\),所求为\[\sum_{i=1}^ndis(i,u)^k\] 把后面那堆东西化成第二类斯特林数,有\[\sum_{i=1}^n\sum_{j=0}^kS(k,j)\times ... 
- BZOJ 2159: Crash 的文明世界(组合数学+第二类斯特林数+树形dp)
		传送门 解题思路 比较有意思的一道数学题.首先\(n*k^2\)的做法比较好想,就是维护一个\(x^i\)这种东西,然后转移的时候用二项式定理拆开转移.然后有一个比较有意思的结论就是把求\(x^i\) ... 
- 【BZOJ2159】Crash的文明世界(第二类斯特林数,动态规划)
		[BZOJ2159]Crash的文明世界(第二类斯特林数,动态规划) 题面 BZOJ 洛谷 题解 看到\(k\)次方的式子就可以往二项式的展开上面考,但是显然这样子的复杂度会有一个\(O(k^2)\) ... 
- 国家集训队 Crash 的文明世界(第二类斯特林数+换根dp)
		题意  题目链接:https://www.luogu.org/problem/P4827  给定一棵 \(n\) 个节点的树和一个常数 \(k\) ,对于树上的每一个节点 \(i\) ,求出 \( ... 
- 题解  [BZOJ2159] Crash的文明世界
		题面 解析 这题一眼换根DP啊 首先,我们考虑一下如何转换\(n^m\)这个式子, 先把式子摆出来吧:\(n^m=\sum_{j=0}^mS(m,j)C_n^jj!\) 其中\(S(m,j)\)表示第 ... 
随机推荐
- 洛谷 Atcoder 题解 AT2585 【Colorful Leaderboard】
			目测 普及/提高- 难度. 思路 将 9 种可能的等级存储在数组里,则 min 值为分数为 0 ~ 3199 的颜色种类个数,max 值为 min 值加上分数 >3200 的人数. 特判 若分数 ... 
- Grafana基础
			一.Grafana基础 Grafana是一个开源的指标量监测和可视化工具.官方网站为:https://grafana.com/, 常用于展示基础设施的时序数据和应用程序运行分析.Grafana的das ... 
- Java并发编程系列-(5) Java并发容器
			5 并发容器 5.1 Hashtable.HashMap.TreeMap.HashSet.LinkedHashMap 在介绍并发容器之前,先分析下普通的容器,以及相应的实现,方便后续的对比. Hash ... 
- ARTS-S c语言统计程序运行时间
			#include <stdio.h> #include <sys/time.h> #include <unistd.h> int main() { struct t ... 
- 灵魂拷问:如何检查Java数组中是否包含某个值 ?
			在逛 programcreek 的时候,我发现了一些专注细节但价值连城的主题.比如说:如何检查Java数组中是否包含某个值 ?像这类灵魂拷问的主题,非常值得深入地研究一下. 另外,我想要告诉大家的是, ... 
- hbuilder/hbuilderx 无法检测到模拟器
			常用模拟器的端口 夜神模拟器 端口号 :62001 海马玩模拟器 端口号:26944 网易mumu模拟器端口号:7555 天天模拟器 端口号:6555 AndroidStudio自带模拟器 端口号: ... 
- Java开发数据库设计的14个技巧,你知道几个?
			1. 原始单据与实体之间的关系 可以是一对一.一对多.多对多的关系.在一般情况下,它们是一对一的关系:即一张原始单据对应且只对应一个实体.在特殊情况下,它们可能是一对多或多对一的关系,即一张原始单证对 ... 
- ajax request 等请求的数据直接return
- 《Java数据结构》链表结构(单向链表,双向链表)
			单向链表(单链表)是链表的一种,其特点是链表的链接方向是单向的,对链表的访问要通过顺序读取从头部开始:链表是使用指针进行构造的列表:又称为结点列表,因为链表是由一个个结点组装起来的:其中每个结点都有指 ... 
- webpack构建原理和实现简单webpack
			webpack打包原理分析 基础配置,webpack会读取配置 (找到入口模块) 如:读取webpack.config.js配置文件: const path = require("path& ... 
