アルゴリズム:順列&コンビネーション

組み合わせ数

組合せ論の存在は配置、建設、カウント問題のある条件を満たす離散オブジェクトのセットを研究することです。理論カウントが狭い組み合わせ数学は基礎研究、研究は主に、一定の条件の順列とカウントの問題を満たしているです。カウント原則、カウント、カウント方法、カウント式を含む組成物。

組み合わせ数の基礎

さらに原則

\ [一つの目標が異なる場合に達成することができる場合は、NとI最初のケースのためのさまざまな方法があり、方法のその後総数N \\、M_I:N = M_1 + M_2 + ... + m_n = \ sum_ {I = 1} ^ N M_I \]

前記単一の目標を達成するための条件のそれぞれは、他の条件に依存することなく達成することができ、いずれか二つの方法のいずれかの場合には、ユニークです。

乗算原則

nステップの後、ステップkについて、異なる方法で、\\方法の総数Nがm_k場合\ [目標を達成する:Nは= M_1 \回\倍... \回M_2をm_n = \ prod_ {I = 1} ^ N M_I \]

その中でも、そこのステップの間の関係は、トポロジーことですが、それぞれのステップが不可欠であり、各ステップ内の他の工程に影響を与えない方法を選択します。

包除原理

最も重要なことは、組み合わせ数繰り返されていませんがお見逃しなくしかし、ダブルカウントの多くは通常の状況、または分類の議論では、一定の条件の下で生じる漏れ常にあります。その後、我々は包含と除外にする必要があります。包除原理の基本的な考え方をされています。各ステップは、従うべき正しい使用を繰り返すことはできません逃してはいけない理由を持っているので、例数はすべてに来て、その後、いくつかのダブルカウントを除外し、繰り返し考えられません。

式:
\ [セットSは、有限集合であり、a_iを\ subseteq S、I \ Nで^ +、 その後、\\ | \ bigcup_ {I = 1 } ^ N a_iを| = \ sum_ {k = 1} ^ N(-1 )^ {K-1} \ sum_ {1 \ルI_1 <I_2 <... <I_K \ルN} | A_ {I_1} \ bigcap A_ {I_2} \ bigcap ... \ bigcap A_ {I_K} | \ ]
および除外数学的帰納法によって証明、及び式が設定された動作の次の基本方程式(ドモルガン式)により求めることができる
。\ [\上線{\ bigcup_ 1} = {I} ^ N-a_iを= \ bigcap_ 1 = {I} ^ N- \上線{a_iを} \\ \上線 {\ bigcap_ {I = 1} ^ N a_iを} = \ bigcup_ ^ {I 1 =} N \上線{a_iを} \]

コンビネーション・カウントの基本式

配置数式

任意のN M(M≦N)を撮影した異なる要素から構成要素は、(要素の順序が現れた考慮して)行におけるMから採取要素n個の異なる構成要素の既知の配置を配置しました。m個の順列の数、すなわちアレイ配置番号の総数は、N個の異なる要素から抽出要素(順列の数)と呼ばれています。配列番号は、記号P(順列)またはA(配列)によって示されます。
\ [A_N ^ M(P_N ^ M) (順序を考慮する)、mはn個の要素から除去され、得られたプログラムナンバーに配置表します。\\ A_N ^ M = N(N -1)...(NM + 1)= {N!\以上(NM)!} \]

広げます

\ [\ {整列}開始&1.巡回置換:も知ら円形配置、置換N、環状の置換N内部からの要素を構成するM個削除要素の数を指し、N = {A_N ^ M \ Mにわたって} \\&2 。k個のクラスにn個の要素、i番目の要素の数は、要素N = {N!\オーバー\ prod_ {I = 1} ^ K n_i!} \\\エンドNの順列の数は、この時点で、n_iあります] \ {整列}

組み合わせ式の数

任意のN M(M≦N)を撮影した異なる要素から要素のグループ(順序を考慮しない)、m個から採取要素n個の異なる要素の既知の組み合わせを構成します。組み合わせの総数は、m個の組み合わせの数は、n個の異なる要素から抽出要素(組み合わせの数)と呼ばれる、即ち組合せの数です。組み合わせの数は、符号Cで示す:
\ [C_N ^ M、Mは元素Nからなる群から得られた(順序に関係なく)除去プログラムの数を表し、二項係数(_n ^ M)で表すことができます。\\ C_N ^ M = {A_N ^ Mを超えるM \!} = {N!\以上(NM)!M!} \]

広げます

\ [K土類元素、各タイプの要素の無制限、C_ {K + M-1}のM ^ Mからこれらの要素の組み合わせの数\です]

特性の組み合わせの数

\ [\開始{ALIGN}&1.C_n ^ M = C_N ^ {NM} \\&2.mC_n ^ M = NC_ {N-1} ^ {M-1} \\&3组合数递推式:C_N ^ M = C_ {N-1} ^ {M-1} + C_ {N-1} ^ M \\&4二项式系数:\ sum_ {I = 0} ^ N C_N ^ iはC_Nを= ^ 0 + C_N ^ 1 + ... + C_N ^ N = 2 ^ N \\&\空間\空間C_N ^ 0 + C_N ^ 2 +···= C_N ^ 1 + C_N ^ 3 + ... = 2 ^ {N-1} \\&5.C_m ^ M + C_ {M + 1} ^ M + ... + C_ {m + nは} ^ M = C_ {M + N + 1} ^ {M + 1} \\&6.C_n ^ 0 + C_ {N + 1} ^ 1 + ... + C_ {N + M} ^ M = C_ {N + M + 1} ^ M \\&7.C_ {2N} ^ 2 = 2C_n ^ 2 + N ^ 2 \\ \端{ALIGN} \]

错排公式

問題の間違った行は、数学の古典的な問題の一つの組み合わせです。千鳥配置すなわちエラー:n個の要素からなる一つの構成については、各要素が元の位置に、この配置は千鳥オリジナル配列と呼ばれないようにリオーダー。数千鳥は、n個の要素のアレイは、D(n)は、その後のように表される:
\ [\ {ALIGN =左}&D(N)\\ =&N \左の[開始- {1 \ over1 {1 \ over0を}。!。! } + {1 \ over2!} ... + {\ nは上\(右\ ^ -1 N)&= \\左!} \右]!\ CDOT \ sum_ {iが0} ^ = N {( !-1)^ I \ Iオーバー } = N \ CDOT \ sum_ {I = 2} ^ N {( - !! 1)^ I \ Iオーバー} \\ =&\ [{N \} E上に残っています! +0.5 \右(丸い{E上に1 \}によって導入された拡張可能)\端{ALIGN} \]

一般的な技術の組み合わせ数

バンドル法

連続している必要があり、特定の要素を尋ねたとき、その後、一緒に考慮全体および他の要素として、全体としてそれらを置きます。注:全体の内部順序があります。

補間法

隣接する特定の要素を必要としない場合、他の要素が最初に並ぶことができ、次いで、空隙に必要な非隣接の要素または要素の両端が適切に配置されています。

パーティション方法

同じ要素のいくつかのパケットの問題に対処する上で、グループごとに少なくとも1つの元素を必要に応じて、パケットの目的を達成するために、行のこれらの要素の中のグループから1を引いた「スペーサー」の数に挿入することができます。
\ [例:Nボールが箱をM、各ボックスが空ではない、そこC_ {N-1} ^ { M-1} プログラムの種類、ボックスが必要とされない場合、空でないが、Mの導入によるものであってもよい\\ボール、ボールを解決するための分割方法の各ボックスのそれぞれから除去され、プログラム番号C_ {N + M-1} ^ {M-1} \]

  1. A、B、C、D、 E 、A、Bは一緒に立っていない行の5つ、どのように多くの局の合計?
    \ [補間方法:我々はC、D、Eは、プログラム番号A_3 ^ 3を並べ替え与える考えることができるようにAとして、Bは、一緒に立つことができない。\\ 3人は、4つのギャップを出た後、選別、A、乗算原理に従って補間B、プログラム番号A_4 ^ 2、プログラムの総数A_3 ^ 3 \ CDOT A_4 ^ 2 。\]

  2. A、B、C、D、 E 行の5、A、Bは、一緒にどのように多くの局の合計に耐えなければなりませんか?
    \ [バンドル方法:Aので、Bは一緒に立たなければならない、我々は、単に全体として見たA、B、「バンドル」を入れて、全体的な\\次に等しく処理し、C、D、E。\\外部プログラム番号A_4 ^ 4、内部A、Bの、プログラムA_2 ^ 2の数のために。総スキーム:A_2 ^ 2 \ CDOT A_4 ^ 4。\]

  3. そこ表3のプログラム上のプログラムでは、あるその同じ相対的な順序を維持し、2つの新しいプログラム、プログラムのどのように多くの種類を追加しますか?
    \ [{ALIGN}を開始&バンドル+補間方法を方法で\:\\&2例:1 \\&二つの新しいプログラムに隣接、三つのプログラムは、4つの空の、内部配列を考慮し、プログラム全体を持っています原子C_4 ^ 1 \ CDOT A_2 ^ 2 ; \\&2つの示す2人の隣接していない、2〜4個の空の補間プログラム、プログラム番号A_4 ^ 2; \\&次にプログラムすなわちC_4 ^ 1 \ CDOTの総数A_2 ^ 2 + A_4 ^ 2。\端{ALIGN} \]

  4. 三つの異なるボックスに8つの同一のボール、各ボックスには、どのように多くの方法、少なくとも1個のボールを置くために必要な?
    \ [メソッド分離:行の8つのボール、ボール7との間のギャップの数、我々は今、2枚のセパレータ、セパレータ7 \\挿入された2個の空孔を有していることを前提とし、ボールに存在分けることができます3つのボックス、プログラム番号C_7 ^ 2に対応する3つのグループの配列。\]

  5. n個〜3個の、M、K、限り異なるの構成として、同じ数mとすることができるそれらの同等とKそのような行の0〜n-1の数mで選択:イタリアこと(HDU 6397)それはすることができます。質問の意味を満たすためにどのように多くの取り決めの合計を求めて。

\ [N-M球状カートリッジ同様の問題は、空のカセットであってもよいです。かかわらず、サイズ制限番号、プログラムC_ {K + M-1} ^ {M-1}の総数。セット数は、x、そこX_1 + X_2 + ... + x_m = Kである\\。\\ためY_I = X_I + 1、セパレータを分析した:Y_1 + Y_2 + ... + y_m = K + M。\\が、サイズがn内のトピックの数を制限することができ、これを考慮してください。次に、以上のX nがある、私たちの限られた列挙を超えI番号\\、すなわち数mが存在すると仮定このとき番号スキームがある:\\ C_m ^ I \ CDOT C_ {K + M-1-I \倍のn} ^ {M-1}は、対応する分析:\\ X_1 '+ X_2' +··· + x_m「= KI \ n倍。\\最後に、封入排除は奇数プラスにも答えを減らすことができます。\]

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int maxn = 2e5 + 100;
const int mod = 998244353;

ll inv[maxn], F[maxn], Finv[maxn];

void init() {
    inv[1] = 1;
    for(int i = 2; i < maxn; i++)
        inv[i] = (mod - mod / i) * inv[mod % i] % mod;
    F[0] = Finv[0] = 1;
    for(int i = 1; i < maxn; i++) {
        F[i] = F[i - 1] * i % mod;
        Finv[i] = Finv[i - 1] * inv[i] % mod;
    }
}

ll C(ll n, ll m) {
    if(n < 0 || m < 0 || m > n) return 0;
    return F[n] * Finv[m] % mod * Finv[n - m] % mod;
}

int main() {
    int t, n, m, k;
    init();
    cin >> t;
    while(t--) {
        cin >> n >> m >> k;
        ll ans = 0;
        for(int i = 0; i * n <= k; i++) {
            int r = C(m, i) * C(k - i * n + m - 1, m - 1) % mod;
            if(i & 1) ans = (ans - r + mod) % mod;
            else ans = (ans + r) % mod;
        }
        cout << ans << endl;
    }
    return 0;
}
  1. kの(UVA 10943)は非負の整数の需要を超えてNそのようなプログラムおよびnの数になりません。方法セパレータは、カセットを空にすることができます。データ範囲は比較的小さいので、全ての前DP、O(1)クエリの直接の結果。

    #include<bits/stdc++.h>
    using namespace std;
    const int mod = 1e6;
    int n, k, dp[111][111]; // dp[i][j]表示用j个数使得和为i的方案数
    int main() {
     for (int i = 1; i <= 100; i++) {
         dp[i][1] = 1;
         dp[1][i] = i;
     }
     for (int i = 2; i <= 100; i++)
         for (int j = 2; j <= 100; j++)
             dp[i][j] = (dp[i - 1][j] + dp[i][j - 1]) % mod;
     while (cin >> n >> k && (n|k)) { 
            cout << dp[n][k] << endl;
     }
        return 0;
    }
  2. (CF GYM 100548)nがMで塗装花の色、隣接する異なる色の要件、およびKであると正確な色の数を使用して配置されています。プログラム%の1E9 + 7の番号を探しています。

    分析:包含と除外の+乗算原則。
    \ [\ {ALIGN}&Mは、代替的にkに色の最初の色から選択されたプログラム番号C_m ^ Kを開始し、\\&乗算原理:最初の花のために、各後続のK選択肢は、あります花、&​​\\のみ(K-1)の選択肢を確保するために繰り返さない、プログラムナンバー&\\ K \倍(K-1) ^ {N-1}。\\&が、色を使用して、この時間は、欠陥の離職数kプログラムの数は除外包除原理を必要と含まれています。\\&塗装I Kの色で考慮から採取し、プログラムナンバーC_k ^ I \ CDOT P(P -1)^ {N-1}、 奇数撥結合能の低下があっても、増加を描くことができる:\\ &全体のプログラム数N = C_m ^ K \ CDOT K (K-1)^ {N-1} + \ sum_ {I = 2} ^ {K-1}( - 1)^ iC_k ^ I \ CDOT I(I -1)^ {N-1} \\& 明らかに、組み合わせの数を逆元を使用する必要があり、迅速な電源、標準プロセス以下。\端{ALIGN} \]

    #include <iostream>
    using namespace std;
    typedef long long ll;
    
    const int mod = 1e9 + 7;
    const int maxn = 1000010;
    
    ll ans, inv[maxn], F[maxn], Finv[maxn];
    
    ll qpow(ll a, ll b) {
        ll ans = 1;
        while(b) {
            if(b & 1) ans = (ans * a) % mod;
            b >>= 1; a = (a * a) % mod;
        }
        return ans;
    }
    
    void init() {
        inv[1] = 1;
        for(int i = 2; i < maxn; i++)
            inv[i] = (mod - mod / i) * inv[mod % i] % mod;
        F[0] = Finv[0] = 1;
        for(int i = 1; i < maxn; i++) {
            F[i] = F[i - 1] * i % mod;
            Finv[i] = Finv[i - 1] * inv[i] % mod;
        }
    }
    
    ll C(ll n, ll m) {
        if(n < 0 || m < 0 || m > n) return 0;
        return F[n] * Finv[m] % mod * Finv[n - m] % mod;
    }
    
    int main() {
     init();
     int t, kase = 0;
        cin >> t;
        while (t--) {
            cin >> n >> m >> k;
            ans = C(m, k) * k % mod * qpow(k - 1, n - 1) % mod;
            ll sign = 1;
            for(ll i = 2; i < k; i++) {
             ans = (ans + C(k, i) * i % mod * qpow(i - 1, n - 1) % mod * sign + mod) % mod;
             sign = -sign;
            }
            cout << "Case #" << ++kase << ": " << ans << endl;
        }
        return 0;
    }

おすすめ

転載: www.cnblogs.com/Li-F/p/11894612.html