NeFut Logo NeFut
Admin Login

In-depth Analysis of Combinatorial Counting and Algorithm Optimization

Published at: 2026-05-27 09:17 Last updated: 2026-06-06 13:04
#C++ #Tutorial

Core Logic and Mathematical Principles

Combinatorial counting is at the heart of discrete mathematics. In the NOIP competition, all complex counting models can ultimately be reduced to three fundamental pillars: the general term of permutations and combinations, the ball-in-box model (using dividers), and derangements.

1. Basic Formulas for Permutations and Combinations

$$A_n^m = \frac{n!}{(n-m)!} = n \cdot (n-1) \dots (n-m+1)$$

$$C_n^m = \frac{n!}{m!(n-m)!}$$

The combination satisfies the symmetry $C_n^m = C_n^{n-m}$ and the recursive property (Pascal's triangle formula) $C_n^m = C_{n-1}^{m-1} + C_{n-1}^m$.

2. Ball-in-box Model (Using Dividers)

This model is used to solve the counting problem of placing $n$ identical balls into $m$ distinct boxes.

$$C_{n-1}^{m-1}$$

$$C_{n+m-1}^{m-1}$$

3. Derangement

A permutation $$ satisfies that for any $i$, $(i) eq i$. The number of derangements of $n$ elements is denoted as $D_n$. Its mathematical recursive formula is:

$$D_n = (n-1)(D_{n-1} + D_{n-2})$$

Proof of Recursive Logic:
Consider the $n^{th}$ element placed in position $k$ (there are $n-1$ choices, where $k eq n$).


State Design and Algorithm Derivation

When counting within a linear range of multiple queries, directly applying the general term formula is inefficient. We typically need to utilize state preprocessing to achieve $O(1)$ response speed.

$$D[i] = (i - 1) \cdot (D[i - 1] + D[i - 2]) \bmod \text{MOD}$$

This transition only relies on the previous two terms and can fill the state table in linear scan with $O(N)$ complexity.


C++ Standard Source Code

#include <iostream>
#include <vector>

const int MOD = 1000000007;
const int MAXN = 1000000;

long long fact[MAXN + 5];
long long invFact[MAXN + 5];
long long D[MAXN + 5];

// Fast exponentiation
long long quick_power(long long base, long long exp) {
    long long res = 1;
    base %= MOD;
    while (exp > 0) {
        if (exp & 1) res = (res * base) % MOD;
        base = (base * base) % MOD;
        exp >>= 1;
    }
    return res;
}

// Preprocess basic states of combinatorial mathematics and derangement states
void init_structures(int n) {
    // 1. Preprocess combinations
    fact[0] = 1;
    for (int i = 1; i <= n; ++i) fact[i] = (fact[i - 1] * i) % MOD;

    invFact[n] = quick_power(fact[n], MOD - 2);
    for (int i = n; i >= 1; --i) invFact[i - 1] = (invFact[i] * i) % MOD;

    // 2. Preprocess derangement states
    D[1] = 0;
    D[2] = 1;
    for (int i = 3; i <= n; ++i) {
        // Strictly mod-safe addition to prevent overflow
        D[i] = (i - 1) * ((D[i - 1] + D[i - 2]) % MOD) % MOD;
    }
}

// O(1) Retrieve combination
long long C(int n, int m) {
    if (m < 0 || m > n) return 0;
    return fact[n] * invFact[m] % MOD * invFact[n - m] % MOD;
}

// O(1) Solve the ball-in-box model with empty boxes: n identical balls in m distinct boxes
long long balls_in_boxes(int n, int m) {
    return C(n + m - 1, m - 1);
}

int main() {
    std::ios_base::sync_with_stdio(false);
    std::cin.tie(NULL);

    init_structures(MAXN);

    int t;
    if (std::cin >> t) {
        while (t--) {
            int n, m;
            std::cin >> n >> m;
            // Example: Output the combination of choosing m from n elements, and the derangement of n elements
            std::cout << C(n, m) << " " << D[n] << "\n";
        }
    }
    return 0;
}

NOIP Practical Pitfall Guide

  1. Modulo Overflow Due to Missing Modulo in Derangement Multiplication
    When executing D[i] = (i - 1) * (D[i - 1] + D[i - 2]), the maximum value of D[i - 1] + D[i - 2] could approach $2 \times 10^9$. If we do not immediately take modulo before multiplying by the outer (i - 1) (if $i \approx 10^6$), the intermediate result could reach $2 \times 10^{15}$, causing an overflow in int and flipping the sign bit. It is essential to ensure that every addition and multiplication step is followed by % MOD.
  2. Confusion Between Identical and Distinct Balls in the Ball-in-box Model
    The divider method only applies to identical balls and distinct boxes. If the problem states “$n$ distinct balls placed in $m$ distinct boxes”, some contestants may mistakenly apply $C_{n+m-1}^{m-1}$, leading to a complete logical collapse (placing distinct balls into distinct boxes essentially represents the second kind of Stirling number or channel counting model $m^n$). It is crucial to keenly capture the qualifiers "identical" and "distinct" during problem analysis.

Classic NOIP/Luogu Problems

1. Luogu P4071 [SDOI2016] Permutation Counting

2. Luogu P3182 [HAOI2016] Ball Arrangement

Original Source: local://20.2

[h] Back to Home