题面

   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=1n​dp[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∑i​Cn−1i−1​Aki​
   复习一下组合数学的知识, 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树 (逆元的计算)相关推荐

  1. MySQL之InnoDB主键索引的B+树的高度计算

    文章目录 MySQL之InnoDB主键索引的B+树的高度计算 1.高度为2和3.主键bigint类型.一行记录数据大小1k MySQL之InnoDB主键索引的B+树的高度计算 1.高度为2和3.主键b ...

  2. 离散数学与组合数学-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. ...

  3. 大数求乘法逆元c语言,乘法逆元(编程计算)+两道版题

    前言 看到这里的小盆友们千万不要以为这个东西很难,其实就是个1+1->1(1个定义+1个定理->1坨乘法逆元).Let's begin.web 有关乘法逆元定义 这个咱们就不要玩笑了,来, ...

  4. 预处理阶乘和阶乘逆元_计算数字的阶乘| 8086微处理器

    预处理阶乘和阶乘逆元 Problem statement: 问题陈述: Write an assembly language program for calculating the factorial ...

  5. 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 ...

  6. HDU 1166 敌兵布阵 【线段树-点修改--计算区间和】

    敌兵布阵 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submi ...

  7. wpl计算方法_【数据结构】树的应用-计算哈夫曼树的WPL值

    计算哈夫曼树的WPL值 根据给定的n个权值(非负值),计算所构造哈夫曼树的WPL值. 基本要求: (1)根据给定的数据,建立哈夫曼树: (2)输出每个叶子结点的带权路径长度: (3)输出哈夫曼树的WP ...

  8. 【原创】更相减损术 stein算法 欧几里得算法 拓展欧几里得算法 扩展欧几里得算法 逆元的计算与筛法 解模线性方程

    欧几里得 说在前面 数论学复习 Part 6. 然后再来一章CRT和组合数,就飞往概率,以此为跳板去向DP. 计划很美啊你. P.S. 这么说来拉格朗日插值可以说是数论学复习的Part 0了啊. 有一 ...

  9. UVALive 7040 Color (容斥原理 + 组合数学递推公式 + 求逆元 + 基础数论)

    传送门 英文题目: Recently, Mr. Big recieved n owers from his fans. He wants to recolor those owers with m c ...

最新文章

  1. 蓝桥杯“基础练习:特殊回文数
  2. 左神算法基础班3_13深度拷贝含有随机指针的链表
  3. SQL数据库无法附加 823错误修复 连接中断
  4. android:shareduserid获取资源,关于 android:sharedUserId=android.uid.system
  5. jquery 删除字符串最后一个字符的方法
  6. DatePickerDialog 简单用法
  7. mysql 安装目录说明
  8. 下拉推广系统立择火星推荐_下拉词删除都择火星下拉
  9. Codeforces 990E Post Lamps 【暴力】【贪心】
  10. SQL语法精讲(包括建库、建表、建视图、查询、增加、删除、修改)
  11. 2019年美赛建模总结与e题思路
  12. ALPHACAM Desinger 2020.0中文破解版 64位
  13. 38译码器和416译码器
  14. win10专业版开机画面模糊_新买电脑看起来有点糊?一招教你解决Win10屏幕模糊问题...
  15. 老外用VB6写的Windows驱动备份软件
  16. 速卖通热卖产品推荐—2021年速卖通家居行业厨房用品热卖产品趋势
  17. iphone个系列尺寸_iphone12哪个尺寸好 iphone12系列尺寸参数对比
  18. FDE中的金属边界条件和PML边界条件的选取
  19. IE-LAB网络实验室:VPLS技术介绍
  20. OpenGL学习笔记——坐标转换

热门文章

  1. Android学习记录
  2. NLP工具——doccano标注系统自动标注功能使用
  3. linux终端命令行删除当前光标之后内容ctrl +k
  4. php 预编译,预编译的prepare statements 管理, 实现和思路
  5. 智能驾驶仿真场景构建技术
  6. 董宝珍:从股市总市值占GDP比例看本轮牛市的归宿
  7. iOS设备分辨率 UI规范 以及适配
  8. armbian ubuntu 桌面_armbian安装lxde桌面
  9. s60v5用java qq_S60V5手机QQ终于来了,试用感受!
  10. python怎么打开h5文件_python中利用h5py模块读取h5文件中的主键方法