• 2741. 特别的排列 Medium


    给你一个下标从 0 开始的整数数组 nums ,它包含 n 个 互不相同 的正整数。如果 nums 的一个排列满足以下条件,我们称它是一个特别的排列:

     ·对于 0 <= i < n - 1 的下标 i ,要么 nums[i] % nums[i+1] == 0 ,要么 nums[i+1] % nums[i] == 0 。

    请你返回特别排列的总数目,由于答案可能很大,请将它对 109 + 7 取余 后返回。

    示例 1:

    输入:nums = [2,3,6]
    输出:2
    解释:[3,6,2] 和 [2,6,3] 是 nums 两个特别的排列。
    

    示例 2:

    输入:nums = [1,4,3]
    输出:2
    解释:[3,1,4] 和 [4,1,3] 是 nums 两个特别的排列。
    

    提示:

     ·2 <= nums.length <= 14

     ·1 <= nums[i] <= 109

    题目大意:在只有可整除的数字能相邻的情况下计算所有合法排列的数量。

    分析:

    (1)由于可整除的数字可以相邻,因此可整除的两个数之间可以视为有一条无向边,用图的思想处理本题,将每个数字视为一个结点。分别从数组中的每个结点开始进行一次深度优先遍历,计算可以连接所有结点的路径的个数sum,得到的sum即为所求的合法排列的数量;

    (2)由于长度为N的数组有N!种排列,用枚举的方式搜索会超时,因此采用记忆化搜索加速计算。设当前遍历的结点为i,当前的状态为flag,状态flag表示已遍历的结点和未遍历的结点,如flag=0b011001时表示第2、3、6个结点已被遍历,而第1、4、5个结点还没有遍历。因为在相同状态(flag)下遍历i结点,返回的合法排列数量是相同的,所以建立二维数组dp,其中dp[i][flag]表示在状态flag的情况下遍历i结点可获得的合法排列数量,以此记录已遍历过的情况,加速深度优先搜索。

    1. class Solution {
    2. public:
    3. int specialPerm(vector<int>& nums) {
    4. int N=nums.size(),flag=(1<-1,ans=0;
    5. vectorint>> dp(N,vector<int>(1<-1));
    6. function<int(int)> dfs=[&](int root){
    7. if(dp[root][flag]!=-1) return dp[root][flag];
    8. int sum=0;
    9. for(int i=0,f=1;i1){
    10. if(root!=i&&(flag&f)&&!(nums[i]%nums[root]&&nums[root]%nums[i])){
    11. flag^=f;
    12. sum=(sum+dfs(i))%1000000007;
    13. flag^=f;
    14. }
    15. }
    16. return dp[root][flag]=sum;
    17. };
    18. for(int i=0;i0]=1;
    19. for(int i=0,f=1;i1){
    20. flag^=f;
    21. ans=(ans+dfs(i))%1000000007;
    22. flag^=f;
    23. }
    24. return ans;
    25. }
    26. };
  • 相关阅读:
    AcWing.505 火柴排队(离散化&逆序对)
    飞思卡尔 S12 (X)串口下载移植
    趣店预制菜爆火背后,是一场慢节奏的长期主义
    ShardingSphere分片算法(未完待续)
    基于Java毕业设计学生宿舍管理系统源码+系统+mysql+lw文档+部署软件
    【红日靶场】vulnstack4-完整渗透过程
    波奇学C++:抽象类和搜索二叉树
    为什么3ds max渲染效果图有噪点?点进来,CG Magic告诉您!
    1212. 地宫取宝
    C语言变量的定义和赋值
  • 原文地址:https://blog.csdn.net/m0_60444839/article/details/140055805