解:讲一个别的题解里我比较难以理解的地方,就是为什么可以把这两个东西合起来看成某一个连通块指数是2m而别的指数都是m。

其实很好理解,但是别人都略过了......把后面的∑提到∏的前面,然后展开,也可以理解成把∏塞到∑里面。

然后我们就发现对于每个生成树,我们其实有n种选择,分别把某个块的次数变成2m,且每种选择都作为一棵生成树计入贡献,且这回的贡献,一个树内部各个块全部是乘积的形式。


发现贡献与度数有关,又要求所有生成树,于是考虑prufer序列。

如何看待每个点是一个连通块?就是对于一种生成树,实际方案要乘上(点数度数)。代表每条边连哪个点。

这样一个生成树的权值是这个东西:

接下来考虑钦定每个连通块的度数。在prufer序列中每个数的出现次数是度数-1,于是令di = di - 1

首先要把这些点在prufer中排列一下,于是有:

接下来一顿操作,把di!塞到∏里面,(n-2)!提出来,就有个式子。

然后考虑生成函数,推荐这个

关于求等幂和这个式子,实在是不理解...

这东西还要我用vector写多项式......

然后搞来搞去,不管了...

 #include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <vector> typedef long long LL;
const int N = ;
const LL MO = , G = ;
typedef LL arr[N << ];
typedef std::vector<LL> Poly; arr A, B, exp_t, inv_t, inv_t2, f, g, h, p, ex;
int r[N << ], n;
LL m, a[N], pw[N]; inline LL qpow(LL a, LL b) {
a %= MO;
LL ans = ;
while(b) {
if(b & ) ans = ans * a % MO;
a = a * a % MO;
b = b >> ;
}
return ans;
} inline void prework(int n) {
static int R = ;
if(R == n) return;
R = n;
int lm = ;
while(( << lm) < n) lm++;
for(int i = ; i < n; i++) r[i] = (r[i >> ] >> ) | ((i & ) << (lm - ));
return;
} inline void NTT(LL *a, int n, int f) {
prework(n);
for(int i = ; i < n; i++) {
if(i < r[i]) std::swap(a[i], a[r[i]]);
}
for(int len = ; len < n; len <<= ) {
LL Wn = qpow(G, (MO - ) / (len << ));
if(f == -) Wn = qpow(Wn, MO - );
for(int i = ; i < n; i += (len << )) {
LL w = ;
for(int j = ; j < len; j++) {
LL t = a[i + len + j] * w % MO;
a[i + len + j] = (a[i + j] - t) % MO;
a[i + j] = (a[i + j] + t) % MO;
w = w * Wn % MO;
}
}
}
if(f == -) {
LL inv = qpow(n, MO - );
for(int i = ; i < n; i++) a[i] = a[i] * inv % MO;
}
return;
} inline void mul(const LL *a, const LL *b, LL *c, int n) {
int len = ;
while(len < n + n) len <<= ;
memcpy(A, a, n * sizeof(LL)); memset(A + n, , (len - n) * sizeof(LL));
memcpy(B, b, n * sizeof(LL)); memset(B + n, , (len - n) * sizeof(LL));
NTT(A, len, ); NTT(B, len, );
for(int i = ; i < len; i++) c[i] = A[i] * B[i] % MO;
NTT(c, len, -);
memset(c + n, , (len - n) * sizeof(LL));
return;
} inline Poly mul(const Poly &a, const Poly &b) {
int len = , lena = a.size(), lenb = b.size();
while(len < lena + lenb) len <<= ;
Poly ans(lena + lenb - );
for(int i = ; i < lena; i++) A[i] = a[i];
for(int i = ; i < lenb; i++) B[i] = b[i];
memset(A + lena, , (len - lena) * sizeof(LL));
memset(B + lenb, , (len - lenb) * sizeof(LL));
NTT(A, len, ); NTT(B, len, );
for(int i = ; i < len; i++) A[i] = A[i] * B[i] % MO;
NTT(A, len, -);
for(int i = ; i < lena + lenb - ; i++) ans[i] = A[i];
return ans;
} void Inv(const LL *a, LL *b, int n) {
if(n == ) {
b[] = qpow(a[], MO - );
b[] = ;
return;
}
Inv(a, b, n >> );
/// ans = b * (2 - a * b);
memcpy(A, a, n * sizeof(LL)); memset(A + n, , n * sizeof(LL));
memcpy(B, b, n * sizeof(LL)); memset(B + n, , n * sizeof(LL));
NTT(A, n << , ); NTT(B, n << , );
for(int i = ; i < (n << ); i++) b[i] = B[i] * ( - A[i] * B[i] % MO) % MO;
NTT(b, n << , -);
memset(b + n, , n * sizeof(LL));
return;
} inline void getInv(const LL *a, LL *b, int n) {
int len = ;
while(len < n) len <<= ;
Inv(a, b, len);
memset(b + n, , (len - n) * sizeof(LL));
return;
} inline Poly getInv(const Poly &a) {
int n = a.size(), len = ;
while(len < n) len <<= ;
for(int i = ; i < n; i++) inv_t[i] = a[i];
memset(inv_t + n, , (len - n) * sizeof(LL));
getInv(inv_t, inv_t2, n);
Poly ans(n);
for(int i = ; i < n; i++) ans[i] = inv_t2[i];
return ans;
} inline void der(const LL *a, LL *b, int n) {
for(int i = ; i < n - ; i++) {
b[i] = a[i + ] * (i + ) % MO;
}
b[n - ] = ;
return;
} inline void ter(const LL *a, LL *b, int n) {
for(int i = n - ; i >= ; i--) {
b[i] = a[i - ] * qpow(i, MO - ) % MO;
}
b[] = ;
return;
} inline void getLn(const LL *a, LL *b, int n) {
getInv(a, inv_t, n);
der(a, A, n);
int len = ;
while(len < n + n) len <<= ;
memset(A + n, , (len - n) * sizeof(LL));
memcpy(B, inv_t, n * sizeof(LL)); memset(B + n, , (len - n) * sizeof(LL));
NTT(A, len, ); NTT(B, len, );
for(int i = ; i < len; i++) b[i] = A[i] * B[i] % MO;
NTT(b, len, -);
memset(b + n, , (len - n) * sizeof(LL));
ter(b, b, n);
return;
} void Exp(const LL *a, LL *b, int n) {
if(n == ) {
b[] = ;
b[] = ;
return;
}
Exp(a, b, n >> );
/// ans = b * (1 + a - ln b)
getLn(b, exp_t, n);
for(int i = ; i < n; i++) A[i] = (a[i] - exp_t[i]) % MO;
A[] = (A[] + ) % MO;
memset(A + n, , n * sizeof(LL));
memcpy(B, b, n * sizeof(LL)); memset(B + n, , n * sizeof(LL));
NTT(A, n << , ); NTT(B, n << , );
for(int i = ; i < (n << ); i++) b[i] = A[i] * B[i] % MO;
NTT(b, n << , -);
memset(b + n, , n * sizeof(LL));
return;
} inline void getExp(const LL *a, LL *b, int n) {
int len = ;
while(len < n) len <<= ;
Exp(a, b, len);
memset(b + n, , (len - n) * sizeof(LL));
return;
} inline void out(const Poly &a) {
//printf("siz = %d ", a.size());
for(int i = ; i < a.size(); i++) {
printf("%lld ", (a[i] + MO) % MO);
}
printf("\n");
return;
} Poly dvd(int l, int r) {
if(l == r) {
Poly res();
res[] = ; res[] = -a[r];
return res;
}
int mid = (l + r) >> ;
Poly ans = mul(dvd(l, mid), dvd(mid + , r));
return ans;
} inline void solve1() {
Poly q = dvd(, n);
Poly p(n);
for(int i = ; i < n; i++) {
p[i] = q[i] * (n - i) % MO;
}
p = mul(p, getInv(q));
for(int i = ; i < n; i++) {
ex[i] = p[i];
//printf("ex %d = %lld \n", i, ex[i]);
}
return;
} int main() { scanf("%d%lld", &n, &m);
for(int i = ; i <= n; i++) {
scanf("%lld", &a[i]);
}
///
solve1(); pw[] = ;
for(int i = ; i <= n; i++) pw[i] = pw[i - ] * i % MO;
for(int i = ; i < n; i++) {
f[i] = qpow(i + , m) * qpow(pw[i], MO - ) % MO;
h[i] = qpow(i + , m << ) * qpow(pw[i], MO - ) % MO;
}
getInv(f, p, n);
mul(p, h, h, n); getLn(f, g, n);
for(int i = ; i < n; i++) {
g[i] = g[i] * ex[i] % MO;
h[i] = h[i] * ex[i] % MO;
}
getExp(g, f, n); mul(h, f, f, n); LL ans = f[n - ];
for(int i = ; i < n - ; i++) ans = ans * i % MO;
for(int i = ; i <= n; i++) ans = ans * a[i] % MO; if(ans < ) ans += MO;
printf("%lld\n", ans); return ;
}

AC代码

LOJ#2320 生成树计数的更多相关文章

  1. Loj 2320.「清华集训 2017」生成树计数

    Loj 2320.「清华集训 2017」生成树计数 题目描述 在一个 \(s\) 个点的图中,存在 \(s-n\) 条边,使图中形成了 \(n\) 个连通块,第 \(i\) 个连通块中有 \(a_i\ ...

  2. 【BZOJ1002】【FJOI2007】轮状病毒(生成树计数)

    1002: [FJOI2007]轮状病毒 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 1766  Solved: 946[Submit][Status ...

  3. SPOJ 104 HIGH - Highways 生成树计数

    题目链接:https://vjudge.net/problem/SPOJ-HIGH 解法: 生成树计数 1.构造 基尔霍夫矩阵(又叫拉普拉斯矩阵) n阶矩阵 若u.v之间有边相连 C[u][v]=C[ ...

  4. Luogu P5296 [北京省选集训2019]生成树计数

    Luogu P5296 [北京省选集训2019]生成树计数 题目链接 题目大意:给定每条边的边权.一颗生成树的权值为边权和的\(k\)次方.求出所有生成树的权值和. 我们列出答案的式子: 设\(E\) ...

  5. 「UVA10766」Organising the Organisation(生成树计数)

    BUPT 2017 Summer Training (for 16) #6C 题意 n个点,完全图减去m条边,求生成树个数. 题解 注意可能会给重边. 然后就是生成树计数了. 代码 #include ...

  6. SPOJ.104.Highways([模板]Matrix Tree定理 生成树计数)

    题目链接 \(Description\) 一个国家有1~n座城市,其中一些城市之间可以修建高速公路(无自环和重边). 求有多少种方案,选择修建一些高速公路,组成一个交通网络,使得任意两座城市之间恰好只 ...

  7. BZOJ1494 [NOI2007]生成树计数

    题意 F.A.Qs Home Discuss ProblemSet Status Ranklist Contest 入门OJ ModifyUser  autoint Logout 捐赠本站 Probl ...

  8. Organising the Organisation(uva10766)(生成树计数)

    Input Output Sample Input 5 5 2 3 1 3 4 4 5 1 4 5 3 4 1 1 1 4 3 0 2 Sample Output 3 8 3 题意: 有一张图上有\( ...

  9. 【BZOJ1494】【NOI2007】生成树计数(动态规划,矩阵快速幂)

    [BZOJ1494][NOI2007]生成树计数(动态规划,矩阵快速幂) 题面 Description 最近,小栋在无向连通图的生成树个数计算方面有了惊人的进展,他发现: ·n个结点的环的生成树个数为 ...

随机推荐

  1. Redis主从复制原理总结

    和Mysql主从复制的原因一样,Redis虽然读取写入的速度都特别快,但是也会产生读压力特别大的情况.为了分担读压力,Redis支持主从复制,Redis的主从结构可以采用一主多从或者级联结构,Redi ...

  2. python基础学习笔记(三)

    序列概览 Python 包含6 种内建的序列,这里重点讨论最常用的两种类型:列表和元组. 列表与元组的主要区别在于,列表可以修改,元组则不能.也就是说如果要根据要求来添加元素,那么列表可以会更好用:而 ...

  3. python-深浅copy-18

    # 赋值运算l1 = [1,2,3]l2 = l1l1.append('a')print(l1,l2) # [1, 2, 3, 'a'] [1, 2, 3, 'a'] #copyl1 = [1,2,3 ...

  4. 【个人博客作业II】代码复审结果

    [代码复审结果] General Does the code work? Does it perform its intended function, the logic is correct etc ...

  5. PolarCode

    什么是polar code极化码 为了实现可靠的信号传输,编码学家在过去的半个多世纪提出多种纠错码技术如里所码(RS码).卷积码,Turbo码等,并在各种通信系统中取得了广泛的应用.但是以往所有实用的 ...

  6. Maven遇到github引用的项目有bug怎么办?

    Maven遇到github引用的项目有bug,自己想要修复/作者已经修复了但是还没有版本出来. 一个maven的做法 git clone 该项目(可能直接下载zip比较快). 在项目中mvn inst ...

  7. 《Multiplayer Game Programming》阅读笔记

    在图书馆发现一本<网络多人游戏架构与编程>-- Joshua Glazer, Sanjay Madhav 著.书挺新的,17年出版的,内容很有趣,翻一翻可以学到不少在<计算机网络&g ...

  8. React16新特性

    React的16版本采用了MIT开源许可证,新增了一些特性. Error Boundary render方法新增返回类型 Portals 支持自定义DOM属性 setState传入null时不会再触发 ...

  9. shell of leetcode

    1.Tenth Line How would you print just the 10th line of a file? For example, assume that file.txt has ...

  10. linux shell $ 特殊变量

    $0   #Shell本身的文件名 $1-$n   #添加到Shell的各参数值.$1是第1参数.$2是第2参数… $*   #所有参数列表.如"$*"用「"」括起来的情 ...