算法 {排列,排列数}

文章探讨了在模数为质数时计算排列数的两种方法,包括O(logN)查询和O(N*logN)预处理的解决方案。还提到了直接暴力解法,并指出并非所有排列组合问题都有直接对应的公式,有时需要递推求解。此外,文章还涉及了组合问题,如在m*n的方格中放置小球的方案数,以及与之相关的组合计数问题。
摘要由CSDN通过智能技术生成

算法 {排列,排列数}

排列

定義

#標準排列#
序列A[n]裏 所有元素為{1,2,3,...,n};
. 比如[3,1,4,2]是一個排列;

@DELI;

#(一般)排列#
序列A[n]裏 所有元素均不同;
. 比如[33,11,44,22]是一個排列 (因爲他可以離散化為[3,1,4,2] 成爲標準排列);

算法

将任意排列等价于标准排列{0,1,2,3...}, 即将C(n,k)优化为O(1)

比如 你的DP定义是DP( vector<int> nums, m), 其中nums = 从[0,n)中任意选择k个不同的数 所组成的集合, DP表示所有nums所表示的排列中 满足某种要求m的合法排列 (比如nums.size()=3, n=5 那么nums可以等于{0,1,2}, {0,1,3}, {0,1,4}, {0,2,3}, ..., 比如nums={0,2,4} 那么他可以表示[024, 042, 204, ...]这些排列);

他的时间复杂度是 C(n,k) * m, 而假如说 你可以证明 不管nums等于多少 只要nums.size()不变 那么他们的DP值是一样的, 即DP( {0,1,2}, m) == DP({0,1,3}, m) == DP({2,3,4}, m) == DP({0,1,4}, m), 那么 你可以将DP 优化为DP( k, m) 其中k == nums.size() 这是因为 对于C(n,k)的任意方案 他们的DP值都一样 因此任意的DP( nums, m) == DP( {0,1,2}, m) (假设nums.size()==3), 因此 之前nums的种类是C(n,k) 现在种类是1个 即{0,1,2,3...}这个连续递增集合;

例题: @LINK: https://editor.csdn.net/md/?not_checkout=1&articleId=140069535;

性质

#交換排列中的兩個不同元素, 逆序對個數會產生奇偶性變化#
任意一個排列...A[i]...A[j]... 假設此時逆序對個數為X0, 令排列...A[j]...A[i]...的逆序對個數為X1, 那麽X0,X1的奇偶性是不同的;
. 比如排列[12345] 交换两个元素后[14325], 原逆序对个数为0 现在逆序对为3, 奇偶性不同;
. 注意, 這裏講的是排列 (即所有元素都不同), 而不是序列 , 比如序列[322]2逆序對 交換后變成[223]0個 奇偶相同;

@DELI;

#证明#
若原逆序对个数为 a a a, 交换后的个数为 b b b, 我们要证明: a + b a+b a+b为奇数;

一个排列: ... [A] [mid] [B] ..., 将其所有逆序对分为2类:
1 一个逆序对(x,y), [x = A, 则y = mid/B]–OR–[y = B, 则x = A/mid];
. 换句话说, 当我们swap(A,B), 这一类的逆序对 不再是逆序对了;
2 否则, 为此类逆序对, 假设有X个;

[mid]的长度为L, 且mid中有a_less < A < A <A的 (即有L - a_less > A > A >A的), 有b_greater > B > B >B的 (即有L - b_greater < B < B <B的);
f = 1 f=1 f=1如果 A > B A>B A>B, 否则 f = 0 f = 0 f=0;

未交换前, 逆序对个数为: X + a_less + b_greater + f;
交换之后的逆序对个数为: X + (L - a_less) + (L - b_greater) + (1 - f);
. 他俩的和, 是奇数;

@DELI;

排列数

算法

模數為質數|查詢O(logN)|預處理O(N)

@LINK: (https://editor.csdn.net/md/?not_checkout=1&articleId=134768975)-(@LOC_0);

模數為質數|查詢O(1)|預處理O(N*logN)

@LINK: (https://editor.csdn.net/md/?not_checkout=1&articleId=134768975)-(@LOC_1);

直接暴力

template< class _RetType_, class _T> _RetType_ ___GetPermutation_brutal( _T _n, _T _m){
    if( false == (_n>=_m && _m>=0)){ return 0;}
    _RetType_ ANS = 1;
    for( auto i = _m-1; i >= 0; --i){ ANS *= (_n - i);}
    return ANS;
} // ___GetPermutation_brutal

@DELI;

可以(非質數)取模, 也可以不取模

例题

汇总

@LINK: https://editor.csdn.net/md/?not_checkout=1&articleId=133279832
从树中除掉若干点后 树变成了若干个连通块;

@DELI;

LINK: https://editor.csdn.net/md/?articleId=129215215;

@DELI;

一个 m ∗ n m * n mn的方格, 放入 k ≤ m i n ( m , n ) k \leq min(m,n) kmin(m,n)个小球, 使得同一行和同一列内 最多有 1 1 1个小球;
方案数为 C m k ∗ C n k ∗ k ! C_m^k * C_n^k * k! CmkCnkk!;
. C m k ∗ C n k C_m^k * C_n^k CmkCnk相当于是选了一个 k ∗ k k*k kk的正方形, 然后放 k k k个小球; 令 ( c 1 , c 2 , . . . , c k ) (c_1, c_2, ..., c_k) (c1,c2,...,ck) 其中 c i c_i ci表示第 i i i行的小球 所处的列号; 显然, 有 k ∗ ( k − 1 ) ∗ . . . ∗ 1 k * (k-1) * ... * 1 k(k1)...1种方案;
. 该式可以继续化简为: C m k ∗ P m k C_m^k * P_m^k CmkPmk;

@Delimiter

錯誤

#並不是所有的排列組合問題 他的答案 都對應著一個公式 (比如 C n k ∗ ( n − 1 ) k C_n^k * (n-1)^k Cnk(n1)k 然後把你的參數 直接套進這個公式裡 就得到答案了)#
有些情況 你得不到這樣的 直接公式, 只能通過一步步的 遞推來進行; @LINK: @LOC_3

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值