[组合数学] NC13611树 (逆元的计算)
题面
link 有一颗树,树有n个结点。有k种不同颜色的染料给树染色。一个染色方案是合法的,当且仅当对于所有相同颜色的点对(x,y),x到y的路径上的所有点的颜色都要与x和y相同。请统计方案数。
其中,n,k≤300n, k ≤ 300n,k≤300
分析
若是从某个根节点在dfs 或者 bfs 过程中统计,是非常麻烦的事。子结点和父亲一个颜色,这种情况还比较简单,若是不同颜色,则其兄弟结点也不能和该子结点一个颜色(因为这两者通过父结点连接),这样整个过程就不好计算了。
或许可以换一种思路,若是我们已经涂了一个部分,并且这些部分是联通的,即涂了这棵树一棵结点数为 iii 的子树,这棵树共有 jjj 种不同颜色,那么可以记涂法为 dp[i][j]dp[i][j]dp[i][j], 若是已经涂过颜色的 vpv_pvp 与 没有涂过颜色的 vqv_{q}vq 相连,那么可以扩展,若 Color(vp)=Color(vq)Color(v_p) = Color(v_q)Color(vp)=Color(vq),那么 vqv_{q}vq 有一种涂法;若是Color(vp)≠Color(vq)Color(v_p) ≠ Color(v_q)Color(vp)=Color(vq),那么 vqv_{q}vq 有 k−jk - jk−j 种涂法(已经涂过的 jjj 种颜色不能再用了,因为 vqv_qvq 与已经涂过颜色的结点之间的路径必须经过 vpv_pvp)。于是可以得到如下转移式子:
dp[i][j]=dp[i−1][j]+dp[i−1][j−1]∗(k−j+1)dp[i][j] = dp[i-1][j] + dp[i-1][j-1] * (k - j + 1)dp[i][j]=dp[i−1][j]+dp[i−1][j−1]∗(k−j+1)
而我们所需要的答案就是 ∑i=1ndp[n][i]\sum_{i=1}^{n}dp[n][i]∑i=1ndp[n][i],复杂度为 O(nk)O(nk)O(nk) 所以通过动态规划得出答案就可以。
#include <bits/stdc++.h>using namespace std;
typedef long long ll;
typedef pair<int, long long> P;
const int maxn = 1e5 + 10;
const int INF = 0x3f3f3f3f;
const ll mod = 1e9 + 7;ll dp[302][302], ans;
int n, k;int main()
{scanf("%d %d", &n, &k);dp[1][1] = k; //一个结点涂一种颜色有k种答案for(int i = 2; i <= n; i++)for(int j = 1; j <= k; j++) //进行dp{dp[i][j] = dp[i-1][j] + dp[i-1][j-1] * (k - j + 1);dp[i][j] %= mod;}for(int i = 1; i <= k; i++) //累加答案ans = (ans + dp[n][i]) % mod;printf("%lld\n", ans);
}
或许还可以这样想,相同颜色的结点即构成一个连通块,而对于树来说,每切去一条边就多一个连通块,最多可以切去 n−1n - 1n−1 条边,形成 nnn 个连通块。所以一棵树我们有 Cn−1i−1(1≤i≤n)C_{n-1}^{i-1} (1 ≤ i ≤ n)Cn−1i−1(1≤i≤n) 种切法,每次对于得到的 iii 个连通块,用 kkk 种颜色去涂,总共有 AkiA_k^iAki 种涂法,所以最终答案为:
∑niCn−1i−1Aki\sum_n^iC_{n-1}^{i-1}A_k^in∑iCn−1i−1Aki
复习一下组合数学的知识, Cmn=m!(m−n)!n!C_m^n = \frac{m !}{(m-n) !n !}Cmn=(m−n)!n!m!, Amn=m!(m−n)!A_m^n = \frac{m !}{(m-n) !}Amn=(m−n)!m!, 其中阶乘我们可以先预处理出来,但这里有除法的取模,我们需要用到费马小定理: 对于质数 ppp, 若 aaa 不是 ppp 的倍数,则有 ap−1≡1(modp)a^{p-1} ≡ 1 (mod \ p)ap−1≡1(mod p)
那么若记 a−1≡b(modp)a^{-1} ≡ b(mod \ p)a−1≡b(mod p), 那么 a−1∗ap−1≡b∗ap−1(modp)a^{-1} * a^{p-1}≡ b * a^{p-1}(mod \ p)a−1∗ap−1≡b∗ap−1(mod p), 又由于费马小定理可得 b∗ap−1=b(modp)b * a^{p-1} = b (mod \ p)b∗ap−1=b(mod p), 于是 ap−2≡b(modp)a^{p-2} ≡ b(mod \ p)ap−2≡b(mod p), 这样就将一个求负幂次的形式变成了求正幂次的形式,这样我们可以用快速幂 O(logn)O(logn)O(logn) 的时间进行计算了,这样总复杂度就是 O(nlogn)O(nlogn)O(nlogn)
#include <bits/stdc++.h>using namespace std;
typedef long long ll;
typedef pair<int, long long> P;
const int maxn = 1e5 + 10;
const int INF = 0x3f3f3f3f;
const ll mod = 1e9 + 7;ll fac[302], ans;
int n, k;ll qpow(ll x, ll n) //快速幂
{ll t = 1;for (; n; n >>= 1, x = x * x % mod)if (n & 1)t = t * x % mod;return t;
}ll C(int n, int k)
{return fac[n] * qpow(fac[k] * fac[n-k] % mod, mod - 2) % mod;
}ll A(int n, int k)
{return fac[n] * qpow(fac[n-k] % mod, mod - 2) % mod;
}int main()
{scanf("%d %d", &n, &k);fac[0] = fac[1] = 1;for(int i = 2; i <= n; i++) //预处理阶乘fac[i] = fac[i-1] * i % mod;for(int i = 1; i <= min(n, k); i++)ans = (ans + C(n - 1, i - 1) * A(k, i) % mod) % mod;printf("%lld\n", ans);
}
上面用快速幂求逆元用了对数时间,而其实可以先用线性时间先预处理出逆元,这样总复杂度就可以降到 O(n)O(n)O(n)。i−1i^{-1}i−1 在模 ppp 运算下如何得出呢?
不妨记 p=k∗i+rp = k*i + rp=k∗i+r, 其中 r<i,1<i<pr < i,1 < i <pr<i,1<i<p, 那么 k=⌊pi⌋,r=p%ik = ⌊\frac{p}{i}⌋,r = p \%ik=⌊ip⌋,r=p%i, 可以进行如下推导:
k∗i+r≡0(modp)k * i + r ≡ 0 (mod \ p) k∗i+r≡0(mod p)
两边同乘 r−1i−1r^{-1} i^{-1}r−1i−1:
k∗r−1+i−1≡0(modp)i−1≡−k∗r−1(modp)i−1≡−⌊pi⌋∗(p%i)−1(modp)k * r^{-1} + i^{-1} ≡ 0 (mod \ p) \\ i^{-1} ≡ -k*r^{-1}(mod \ p) \\ i^{-1} ≡ - ⌊\frac{p}{i}⌋ * (p \%i)^{-1} (mod \ p)k∗r−1+i−1≡0(mod p)i−1≡−k∗r−1(mod p)i−1≡−⌊ip⌋∗(p%i)−1(mod p)
若记 inv[i]inv[i]inv[i] 表示 iii 的逆元,那么 inv[i]=−p/i∗inv[p%i]inv[i] = - p / i * inv[p \%i]inv[i]=−p/i∗inv[p%i], 调整一下符号,有 inv[i]=(p−p/i)∗inv[p%i]inv[i] = (p - p / i) * inv[p \%i]inv[i]=(p−p/i)∗inv[p%i], 然后算组合数的时候由于求的是阶乘,所以还要前缀和处理一下。
#include <bits/stdc++.h>using namespace std;
typedef long long ll;
typedef pair<int, long long> P;
const int maxn = 1e5 + 10;
const int INF = 0x3f3f3f3f;
const ll mod = 1e9 + 7;ll inv[302], fac[302], ans;
int n, k;ll A(int n, int k)
{return fac[n] * inv[n-k] % mod;
}ll C(int n, int k)
{return fac[n] * inv[k] % mod * inv[n-k] % mod;
}int main()
{scanf("%d %d", &n, &k);inv[0] = inv[1] = 1;fac[0] = fac[1] = 1;for(int i = 2; i <= n; i++) //求逆元和阶乘{inv[i] = (mod - mod / i) * inv[mod % i] % mod;fac[i] = fac[i-1] * i % mod;}for(int i = 2; i <= n; i++) //对阶乘进行前缀和处理inv[i] = inv[i] * inv[i-1] % mod;for(int i = 1; i <= min(n, k); i++)ans = (ans + C(n - 1, i - 1) * A(k, i) % mod) % mod;printf("%lld\n", ans);
}
[组合数学] NC13611树 (逆元的计算)相关推荐
- MySQL之InnoDB主键索引的B+树的高度计算
文章目录 MySQL之InnoDB主键索引的B+树的高度计算 1.高度为2和3.主键bigint类型.一行记录数据大小1k MySQL之InnoDB主键索引的B+树的高度计算 1.高度为2和3.主键b ...
- 离散数学与组合数学-05树
文章目录 离散数学与组合数学-05树 5.1 认识树 5.1.1 树的模型 5.1.2 树的应用 5.2 无向树 5.2.1 定义 5.2.2 树的性质 5.2.3 性质应用 5.3 生成树 5.3. ...
- 大数求乘法逆元c语言,乘法逆元(编程计算)+两道版题
前言 看到这里的小盆友们千万不要以为这个东西很难,其实就是个1+1->1(1个定义+1个定理->1坨乘法逆元).Let's begin.web 有关乘法逆元定义 这个咱们就不要玩笑了,来, ...
- 预处理阶乘和阶乘逆元_计算数字的阶乘| 8086微处理器
预处理阶乘和阶乘逆元 Problem statement: 问题陈述: Write an assembly language program for calculating the factorial ...
- 2019 ACM/ICPC 全国邀请赛(西安)J And And And (树DP+贡献计算)
Then n - 1n−1 lines follow. ii-th line contains two integers f_{a_i}(1 \le f_{a_i} < i)fai(1≤fa ...
- HDU 1166 敌兵布阵 【线段树-点修改--计算区间和】
敌兵布阵 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submi ...
- wpl计算方法_【数据结构】树的应用-计算哈夫曼树的WPL值
计算哈夫曼树的WPL值 根据给定的n个权值(非负值),计算所构造哈夫曼树的WPL值. 基本要求: (1)根据给定的数据,建立哈夫曼树: (2)输出每个叶子结点的带权路径长度: (3)输出哈夫曼树的WP ...
- 【原创】更相减损术 stein算法 欧几里得算法 拓展欧几里得算法 扩展欧几里得算法 逆元的计算与筛法 解模线性方程
欧几里得 说在前面 数论学复习 Part 6. 然后再来一章CRT和组合数,就飞往概率,以此为跳板去向DP. 计划很美啊你. P.S. 这么说来拉格朗日插值可以说是数论学复习的Part 0了啊. 有一 ...
- UVALive 7040 Color (容斥原理 + 组合数学递推公式 + 求逆元 + 基础数论)
传送门 英文题目: Recently, Mr. Big recieved n owers from his fans. He wants to recolor those owers with m c ...
最新文章
- 蓝桥杯“基础练习:特殊回文数
- 左神算法基础班3_13深度拷贝含有随机指针的链表
- SQL数据库无法附加 823错误修复 连接中断
- android:shareduserid获取资源,关于 android:sharedUserId=android.uid.system
- jquery 删除字符串最后一个字符的方法
- DatePickerDialog 简单用法
- mysql 安装目录说明
- 下拉推广系统立择火星推荐_下拉词删除都择火星下拉
- Codeforces 990E Post Lamps 【暴力】【贪心】
- SQL语法精讲(包括建库、建表、建视图、查询、增加、删除、修改)
- 2019年美赛建模总结与e题思路
- ALPHACAM Desinger 2020.0中文破解版 64位
- 38译码器和416译码器
- win10专业版开机画面模糊_新买电脑看起来有点糊?一招教你解决Win10屏幕模糊问题...
- 老外用VB6写的Windows驱动备份软件
- 速卖通热卖产品推荐—2021年速卖通家居行业厨房用品热卖产品趋势
- iphone个系列尺寸_iphone12哪个尺寸好 iphone12系列尺寸参数对比
- FDE中的金属边界条件和PML边界条件的选取
- IE-LAB网络实验室:VPLS技术介绍
- OpenGL学习笔记——坐标转换
热门文章
- Android学习记录
- NLP工具——doccano标注系统自动标注功能使用
- linux终端命令行删除当前光标之后内容ctrl +k
- php 预编译,预编译的prepare statements 管理, 实现和思路
- 智能驾驶仿真场景构建技术
- 董宝珍:从股市总市值占GDP比例看本轮牛市的归宿
- iOS设备分辨率 UI规范 以及适配
- armbian ubuntu 桌面_armbian安装lxde桌面
- s60v5用java qq_S60V5手机QQ终于来了,试用感受!
- python怎么打开h5文件_python中利用h5py模块读取h5文件中的主键方法