• 1916. 统计为蚁群构筑房间的不同顺序 费马小定理+快速幂+DFS


    1916. 统计为蚁群构筑房间的不同顺序

    你是一只蚂蚁,负责为蚁群构筑 n 间编号从 0 到 n-1 的新房间。给你一个 下标从 0 开始 且长度为 n 的整数数组 prevRoom 作为扩建计划。其中,prevRoom[i] 表示在构筑房间 i 之前,你必须先构筑房间 prevRoom[i] ,并且这两个房间必须 直接 相连。房间 0 已经构筑完成,所以 prevRoom[0] = -1 。扩建计划中还有一条硬性要求,在完成所有房间的构筑之后,从房间 0 可以访问到每个房间。

    你一次只能构筑 一个 房间。你可以在 已经构筑好的 房间之间自由穿行,只要这些房间是 相连的 。如果房间 prevRoom[i] 已经构筑完成,那么你就可以构筑房间 i

    返回你构筑所有房间的 不同顺序的数目 。由于答案可能很大,请返回对 109 + 7 取余 的结果。

    示例 1:

    输入:prevRoom = [-1,0,1]
    输出:1
    解释:仅有一种方案可以完成所有房间的构筑:0 → 1 → 2
    

    示例 2:

    输入:prevRoom = [-1,0,0,1,2]
    输出:6
    解释:
    有 6 种不同顺序:
    0 → 1 → 3 → 2 → 4
    0 → 2 → 4 → 1 → 3
    0 → 1 → 2 → 3 → 4
    0 → 1 → 2 → 4 → 3
    0 → 2 → 1 → 3 → 4
    0 → 2 → 1 → 4 → 3
    

    提示:

    • n == prevRoom.length
    • 2 <= n <= 105
    • prevRoom[0] == -1
    • 对于所有的 1 <= i < n ,都有 0 <= prevRoom[i] < n
    • 题目保证所有房间都构筑完成后,从房间 0 可以访问到每个房间

    来源:力扣(LeetCode)
    链接:https://leetcode.cn/problems/longest-univalue-path
    著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

    做题结果

    失败,方法完全对,但是不掌握组合数用的费马小定理,就搞不定。1e5的话,不可以用杨辉三角算。上次偷懒没学,这次也不算完全懂,但是会用了

    方法:快速幂+费马小定理+DFS

    1. 费马小定理用在组合数怎么用(因为找了很多资料,还是看不懂,最后大概通过结论猜出怎么用),单从组合数而言,(1/a)%MOD当做 (a^(MOD-2)) 处理

    2. 阶乘:x! 这个简单吧,循环连乘即可,用 inv[i]表示。1/(k!) 可以用费马小定理搞定 用fac[i]表示

    3. 组合公式 ,我们已知 n!,1/(m!),1/(n-m)!,也就是inv[n]*fac[m]*fac[n-m]

    4. a^(MOD-2)) 需要用到快速幂。快速幂简单的数就是折半幂的过程。比如 2^10,我们可以看成是(2^2)^5,然后遇到5,需要单独拆出一个,变成 (2^2)*(2^2)^4=(2^2)*((2^2)^2)^2,这样可以大大减少计算次数,乘法,加法,减法过程可以求余数,防止溢出

    1. private long pow(long a, long b){
    2. long ans = 1L;
    3. while (b>0){
    4. if((b&1)==1){
    5. ans = ans*a%MOD;
    6. }
    7. b=b/2;
    8. a= a*a%MOD;
    9. }
    10. return ans;
    11. }

    5. DFS: 先排好一个子树,假设这个子树本身有 x1 个节点,有 y1 种排法,然后第二个子树的元素,实际上是插入前面元素的空格。比如原本有 x2个节点,则要把这x2个插入 x1+x2的空位之中,然后现在已有节点数目就变成 x1+x2,又当前子树有 y2种排法 y1*c(x1+x2,x2)*y2*c(x1+x2+x3,x3)*y3.....,算完所有子树后即可得到最终结果

    1. class Solution {
    2. long[] fac;
    3. long[] inv;
    4. public int waysToBuildRooms(int[] prevRoom) {
    5. //1.建图
    6. Map> graph = new HashMap<>();
    7. int n = prevRoom.length;
    8. for(int i = 1;i < n; i++){
    9. graph.computeIfAbsent(prevRoom[i],o->new HashSet<>()).add(i);
    10. }
    11. fac = new long[n];
    12. inv = new long[n];
    13. fac[0]=inv[0]=1;
    14. for(int i = 1; i < n; i++){
    15. fac[i] = fac[i-1]*i%MOD;
    16. inv[i] = pow(fac[i],MOD-2);
    17. }
    18. return (int) dfs(graph,-1,0)[0];
    19. }
    20. private long pow(long a, long b){
    21. long ans = 1L;
    22. while (b>0){
    23. if((b&1)==1){
    24. ans = ans*a%MOD;
    25. }
    26. b=b/2;
    27. a= a*a%MOD;
    28. }
    29. return ans;
    30. }
    31. long ans = 0L;
    32. final long MOD = (long) (1e9+7);
    33. //摆法+节点
    34. private long[] dfs(Map> graph, int pre, int index){
    35. if(!graph.containsKey(index) || (graph.size()==1&&graph.containsKey(pre))){
    36. return new long[]{1,1};
    37. }
    38. int total = 0;//总共选了几个点
    39. long ans = 1L;
    40. for(int next:graph.get(index)){
    41. if(next==pre) continue;
    42. long[] item = dfs(graph,index,next);
    43. long c = getC((int)(total+item[1]),(int)item[1]);
    44. ans = ans * c%MOD*item[0]%MOD;
    45. total+=item[1];
    46. }
    47. return new long[]{ans,total+1};
    48. }
    49. private long getC(int a, int b){
    50. return fac[a]*inv[a-b]%MOD*inv[b]%MOD;
    51. }
    52. }

  • 相关阅读:
    最强大脑记忆曲线(12)-- 录入数据修改
    FPGA的基础架构,什么是CLB?
    VL (Vision and Language) 任务简介及数据集
    JVM报错GC overhead limit exceeded
    emlogPro实现模板预览功能(包含模板设置数据)
    CSS网页标题图案和LOGO SEO优化
    课堂教学观察方法与技术——阅读笔记
    Dajngo02_第一个Django案例
    袋鼠云数栈产品中 AI+ 实现原理剖析
    flutter系列之:Material主题的基础-MaterialApp
  • 原文地址:https://blog.csdn.net/yu_duan_hun/article/details/126670510