The Two Types of Contiguous Segments

CCPC 2021 Online H - Subpermutation defines the full-permutation of nn: concatenate all permutations of 11 through nn in lexicographic order to obtain the sequence pnp_n.

Given n,mn,m, count the contiguous subsequences of pnp_n of length mm that are themselves permutations of 11 through mm. Answers for multiple test cases are taken modulo 109+710^9+7, with:

1≤m≤n≤106,T≤105. 1\le m\le n\le 10^6,\qquad T\le 10^5. Problem statement

Each original permutation has length nn, and the segment length mm does not exceed nn. A segment can therefore meet at most two original permutations, and all cases split completely into two types:

  • The segment lies entirely within one permutation;
  • The segment takes a nonempty suffix of one permutation followed by a nonempty prefix of the next.

These two types are disjoint, so count them separately and add the results.

Contributions Within One Permutation

A contiguous segment of length mm is a permutation of 11 through mm if and only if those mm values occupy mm consecutive positions in the current permutation.

First choose the starting position of this block, giving n−m+1n-m+1 choices. The values 11 through mm can be arranged arbitrarily inside the block, and the remaining n−mn-m values can also be arranged arbitrarily. The total number of valid segments lying entirely within a single permutation is therefore:

I=(n−m+1)m!(n−m)!. I=(n-m+1)m!(n-m)!.

This counts across all n!n! permutations together. Each permutation satisfying the condition contributes exactly one valid starting position, with no duplication.

Crossing a Permutation Boundary

Fix the length taken from the end of the preceding permutation as kk, where:

1≤k≤m−1. 1\le k\le m-1.

Let d=m−kd=m-k, and split the preceding permutation PP by position into:

P=A+B+C, P=A+B+C,

Here, ∣A∣=d|A|=d, ∣B∣=n−m|B|=n-m, and ∣C∣=k|C|=k. The segment crossing the boundary consists of CC followed by the length-dd prefix of the successor permutation QQ.

First, require only that AA and CC together contain exactly the values 11 through mm. Then:

  • The values 11 through mm can occupy the mm positions of A,CA,C in any order, giving m!m! choices;
  • The values m+1m+1 through nn can occupy the middle part BB in any order, giving (n−m)!(n-m)! choices.

The number of candidate permutations is:

m!(n−m)! m!(n-m)!

We still need to determine whether prefix AA stays unchanged when moving from PP to its lexicographic successor QQ.

The Subtraction Term from the Longest Decreasing Suffix

To find a permutation’s lexicographic successor, locate its longest decreasing suffix, swap the pivot immediately before that suffix, and put the suffix into its smallest, ascending order.

If B+CB+C is not decreasing, the pivot must lie within B+CB+C, so the length-dd prefix AA remains unchanged. The segment crossing the boundary is then C+AC+A, containing each value from 11 through mm exactly once, and is valid.

Conversely, if all of B+CB+C is decreasing, the lexicographic-successor operation crosses the boundary between AA and B+CB+C. The first dd entries of the successor are no longer exactly the original AA: an element originally to the right of that boundary moves into the prefix. If PP is already the last permutation, it has no successor at all. In either case, CC and the new prefix can no longer form exactly a permutation of 11 through mm.

We therefore only need to subtract the cases where all of B+CB+C is decreasing from the candidate count.

Every value in BB is greater than mm, while every value in CC is at most mm, so their boundary is already decreasing. For all of B+CB+C to be decreasing, it is enough for BB and CC each to be in descending order:

  • Choose the kk values of CC from 11 through mm, giving (mk)\binom{m}{k} choices. Once chosen, their descending order in CC is unique;
  • Arrange the remaining dd values arbitrarily in AA, giving d!d! choices;
  • The descending order of BB is unique.

The subtraction term is therefore:

(mk)d!=(mk)(m−k)!=m!k!. \binom{m}{k}d! =\binom{m}{k}(m-k)! =\frac{m!}{k!}.

For fixed kk, the number of valid segments crossing a boundary is:

Bk=m!(n−m)!−m!k!=m!((n−m)!−1k!). B_k=m!(n-m)!-\frac{m!}{k!} =m!\left((n-m)!-\frac{1}{k!}\right).

Summing over all kk:

B=∑k=1m−1Bk=m!((m−1)(n−m)!−∑k=1m−11k!). \begin{aligned} B &=\sum_{k=1}^{m-1}B_k \\ &=m!\left((m-1)(n-m)!-\sum_{k=1}^{m-1}\frac{1}{k!}\right). \end{aligned}

Combining the Counts into a Closed Form

Add the contributions from within permutations and across their boundaries:

Ans=I+B=(n−m+1)m!(n−m)!+m!((m−1)(n−m)!−∑k=1m−11k!)=m!(n(n−m)!−∑k=1m−11k!). \begin{aligned} Ans &=I+B \\ &=(n-m+1)m!(n-m)! \\ &\quad +m!\left((m-1)(n-m)!-\sum_{k=1}^{m-1}\frac{1}{k!}\right) \\ &=m!\left(n(n-m)!-\sum_{k=1}^{m-1}\frac{1}{k!}\right). \end{aligned}

Ultimately, we need only factorials, inverse factorials, and prefix sums of inverse factorials.

Let:

Si=∑k=1i1k!, S_i=\sum_{k=1}^{i}\frac{1}{k!},

In the implementation, fac[i], ifac[i], and sum[i] maintain i!i!, (i!)−1(i!)^{-1}, and SiS_i, respectively. Each query directly evaluates:

1
return (1ll * n * fac[n - m] % mod - sum[m - 1] + mod) % mod * fac[m] % mod;

All divisions here use modular inverses modulo 109+710^9+7. The preprocessing range is below the modulus, so every factorial has an inverse.

When m=1m=1, the sum is empty and sum[0]=0. The formula gives n(n−1)!=n!n(n-1)!=n!, exactly the number of occurrences of 1 in the full sequence. When n=mn=m, fac[n-m]=fac[0]=1, so the same formula works without an additional branch.

Complexity and Implementation Boundaries

Precompute factorials, inverse factorials, and prefix sums up to 10610^6. This takes O(106+log⁡(109+7))O(10^6+\log(10^9+7)) time and O(106)O(10^6) space. After preprocessing, each query performs only a constant number of modular operations, taking O(1)O(1) per query and O(T)O(T) for all queries.

Three implementation boundaries must also remain consistent:

  • Set fac[0]=1, so 0!0! is available directly when n=mn=m;
  • Start the inverse-factorial prefix sum at ifac[1], so the subtraction term is empty when m=1m=1;
  • For modular subtraction, add mod before taking the remainder to avoid a negative intermediate result.

Final Accepted Code

Expand/collapse the final accepted code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
constexpr int mod = 1e9 + 7, maxn = 1e6 + 5;

ll t, fac[maxn], ifac[maxn], sum[maxn];

ll qpow(ll a, ll b) {
ll res = 1;
a %= mod;
while (b) {
if (b & 1) {
res = res * a % mod;
}
a = a * a % mod;
b >>= 1;
}
return res;
}

void init() {
fac[0] = 1;
for (int i = 1; i < maxn; ++i) {
fac[i] = fac[i - 1] * i % mod;
}
ifac[maxn - 1] = qpow(fac[maxn - 1], mod - 2) % mod;
for (int i = maxn - 2; i >= 0; --i) {
ifac[i] = ifac[i + 1] * (i + 1) % mod;
}
for (int i = 1; i < maxn; ++i) {
sum[i] = (sum[i - 1] + ifac[i]) % mod;
}
}

ll ans(int n, int m) {
return (1ll * n * fac[n - m] % mod - sum[m - 1] % mod + mod) % mod * fac[m] % mod;
}

int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
init();
cin >> t;
while (t--) {
int n, m;
cin >> n >> m;
cout << ans(n, m) << '\n';
}
return 0;
}