Challenge: Permutation Equations
Subdomeniu: Algebra (algebra)
Scor cont: 120.0 / 120
Submission status: Accepted
Submission score: 1.0
Submission ID: 464815717
Limbaj: cpp14
Link challenge: https://www.hackerrank.com/challenges/permutation-equations/problem
Cerinta
Let *N* be a positive integer. Let's define a mapping *f* on the set
of permutations of integers from *1* to *N*, inclusive.
Let *x = (x[1], ..., x[N])* be a permutation of integers from *1*
to *N*, inclusive.
We define the permutation *y = (y[1], ..., y[N])* as follows.
- *y[1] = 1*.
- For *i \> 1* we consider number *z = x[y[i-1]]*.
- If *z* does not equal any of the numbers *y[1], ...,
y[i-1]* then we set *y[i] = z*.
- Otherwise *y[i]* is defined as the smallest integer from *1*
to *N* (inclusive) that does not equal any of the numbers
*y[1], ..., y[i-1]*.
We consider permutation *y* as an image of *x* when mapping *f* is
applied to *x*. That is, we set *f(x) = y*.
Denote by *g(y)* the number of solutions of the equation *f(x) = y*.
That is, *g(y)* is the number of permutations *x* of integers from
*1* to *N*, inclusive, such that *f(x) = y*.
**Challenge**
For the given non-negative integers *L* and *R*, find the number of
permutations *y* of integers from *1* to *N*, inclusive, such that
*L ≤ g(y) ≤ R*. Since this number can be quite large output it modulo (*10<sup>9</sup> + 7*).
**Input Format**
The first line contains an integer *T* denoting the
number of test cases. *T* test cases follow.
Each test case consists of one line which contains three space-separated integers *N, L* and *R*.
**Output Format**
For each test case, output a single line containing P *mod* (10<sup>9</sup>+7), where P is the required number of permutations.
**Constraints**
1 ≤ T ≤ 1000
1 ≤ N ≤ 200,000
0 ≤ L, R ≤ 10<sup>18</sup>
**Sample Input**
4
2 0 0
3 2 2
3 0 10
10 2 1
**Sample Output**
1
1
6
0
**Explanation**
**Example case 1.** The only permutation *y* for which equation *f(x)
= y* has no solutions is *y = (2, 1)*.
**Example case 2.** The only permutation *y* for which equation *f(x)
= y* has *2* solutions is *y = (1, 3, 2)*.
The solutions are *x = (3, 2, 1)* and *x = (3, 1, 2)*.
**Example case 3.** For all *6* permutations *y* of numbers *{1, 2,
3}* we have *0 ≤ g(y) ≤ 10*.
**Example case 4.** Be careful, *L* could be greater than *R*. In
this case the answer is zero.
Cod sursa
#include <bits/stdc++.h>
using namespace std;
static const int MOD = 1000000007;
static const int KMAX = 60; // because R <= 1e18
static inline int addm(int a, int b) {
a += b;
if (a >= MOD) a -= MOD;
return a;
}
static inline int mulm(long long a, long long b) {
return (int)((a * b) % MOD);
}
static int ceil_log2_pos(long long x) {
// x >= 1
int t = 0;
long long v = 1;
while (v < x && t < 62) {
v <<= 1;
++t;
}
return t;
}
static int floor_log2_pos(long long x) {
if (x <= 0) return -1;
int t = 0;
while ((t + 1) < 62 && (1LL << (t + 1)) <= x) ++t;
return t;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T;
cin >> T;
vector<tuple<int,long long,long long>> qs(T);
int nMax = 0;
for (int i = 0; i < T; ++i) {
int N;
long long L, R;
cin >> N >> L >> R;
qs[i] = {N, L, R};
nMax = max(nMax, N);
}
// factorials
vector<int> fact(nMax + 1, 1);
for (int i = 1; i <= nMax; ++i) fact[i] = mulm(fact[i - 1], i);
// unsigned Stirling numbers of first kind: s(n,k), n up to nMax-1, k up to 60.
vector<array<int, KMAX + 1>> stir(nMax);
for (int k = 0; k <= KMAX; ++k) stir[0][k] = 0;
stir[0][0] = 1;
for (int n = 1; n <= nMax - 1; ++n) {
stir[n][0] = 0;
int mul = n - 1;
for (int k = 1; k <= KMAX; ++k) {
int v = stir[n - 1][k - 1];
v = addm(v, mulm(mul, stir[n - 1][k]));
stir[n][k] = v;
}
}
for (auto [N, L, R] : qs) {
if (L > R) {
cout << 0 << '\n';
continue;
}
int m = N - 1; // permutation tail length when y1=1
int ans = 0;
if (N == 1) {
cout << ((L <= 1 && 1 <= R) ? 1 : 0) << "\n";
continue;
}
// Count permutations with g(y)=0 (exactly those with y1 != 1)
if (L <= 0 && 0 <= R) {
int zeroCnt = (fact[N] - fact[m]) % MOD;
if (zeroCnt < 0) zeroCnt += MOD;
ans = addm(ans, zeroCnt);
}
// Positive g values are powers of 2: g = 2^t, t in [1..m]
int loT, hiT;
if (R < 2) {
loT = 1;
hiT = 0; // empty
} else {
loT = (L <= 1 ? 1 : ceil_log2_pos(L));
hiT = floor_log2_pos(R);
}
if (loT <= hiT) {
loT = max(loT, 1);
hiT = min(hiT, m);
if (loT <= hiT) {
int sum = 0;
for (int t = loT; t <= hiT; ++t) {
if (t <= KMAX) sum = addm(sum, stir[m][t]);
}
ans = addm(ans, sum);
}
}
cout << ans << '\n';
}
return 0;
}
HackerRank Algebra – Permutation Equations
