Search for a command to run...
Progressive hints first, then the full explanation and implementation when you're ready to cash out.
Review status
AI-generated and still unreviewed. Double-check the details before internalizing them.
Hints
Open only as much as you need to keep the solve alive.
Stop trying to simulate the while loop for every array. The jumps form increasing chunks: whenever the code follows nxt[pos], the value strictly increases until it hits a position whose value is the current chunk maximum.
For one fixed array, rewrite as a telescoping sum. If the visited indices are split into increasing chunks, each chunk contributes last value - first value. So becomes: sum of chunk-ending maxima, minus sum of values immediately after those maxima, minus .
Now fix . Then the first elements are just a bounded composition of into parts, each between and . Counting these is the real problem; the snake condition becomes boring after fixing .
Use inclusion-exclusion for bounded compositions. Let be the number of arrays of length , sum , and every element at most . Then
For fixed , you only need two counts: and . The first counts all snakes with last value xx\sum_x O(m/(x+1))=O(m\log m)$, which is the whole trick.
Let . Since the array is snake, is the global maximum, and every earlier value is in .
The nasty-looking part is the pseudocode. The counting is not the first boss fight; understanding what the loop actually sums is.
What does the loop compute?
Look at the indices visited by the algorithm:
Some transitions are jumps to nxt[pos], and those jumps strictly increase the value. Some transitions are ordinary pos += 1, which happen only when the current value already equals .
Split the visited sequence right after every visited position whose value is . Inside each block, the jump values strictly increase, so that block contributes:
Adding the blocks telescopes into:
The last maximum is , so there is no “value immediately after it”. This formula is the key. The loop is basically charging every climb, not doing anything mystical. Classic 2800 problem behavior: the code is scarier than the math, because of course it is.
Now we sum this formula over all snake arrays.
Bounded compositions
Define
as the number of arrays of length with sum and all elements between and .
Without the upper bound, the answer is . To enforce , use inclusion-exclusion on elements that exceed :
If , then only when , otherwise .
This can be computed in time.
Fix the maximum
Fix . Then the first elements have sum and each is at most . So the number of such arrays is
We also need the count where a chosen earlier position is forced to equal . After fixing that position and , the remaining positions have sum , still bounded by , so define
Now compute the three parts of the formula.
1. Sum of visited global maxima
Every valid array contributes the last element , giving
Also, any earlier position with value is a global maximum that the algorithm visits by ordinary movement through max positions. For each of the earlier positions, forcing it to be gives arrays. Therefore this part contributes
2. Subtract
Among the first positions, everything is symmetric. Across all arrays counted by , the total sum of those positions is always . Therefore each position contributes the same total sum:
So the total contribution of is
Modulo , division by means multiplying by its modular inverse.
3. Subtract values immediately after earlier global maxima
Take an index with . If , then is immediately after a global maximum. Fixing and , the remaining sum is over positions. By symmetry, the total sum over all choices of these middle following positions is simply
For , if , the value immediately after that maximum is , contributing
So the whole “after maximum” subtraction is
This formula still works when : the middle part is empty, and handles it.
Putting it together
For every from to :
Add
and subtract
All terms are modulo .
The inclusion-exclusion loop for a fixed takes , and we call it twice, so the total complexity is
Since the sum of over tests is at most , this fits easily.
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int MOD = 1000000007;
const int MAXF = 400005;
ll fact[MAXF], invFact[MAXF];
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
ll modPow(ll a, ll e) {
ll r = 1;
while (e) {
if (e & 1) r = r * a % MOD;
a = a * a % MOD;
e >>= 1;
}
return r;
}
void initComb() {
fact[0] = 1;
for (int i = 1; i < MAXF; i++) fact[i] = fact[i - 1] * i % MOD;
invFact[MAXF - 1] = modPow(fact[MAXF - 1], MOD - 2);
for (int i = MAXF - 1; i > 0; i--) invFact[i - 1] = invFact[i] * i % MOD;
}
ll C(int n, int r) {
if (n < 0 || r < 0 || r > n) return 0;
return fact[n] * invFact[r] % MOD * invFact[n - r] % MOD;
}
ll boundedCount(int len, int sum, int mx) {
if (sum < 0) return 0;
if (len == 0) return sum == 0;
ll ans = 0;
int step = mx + 1;
for (int t = 0; t <= len && 1LL * t * step <= sum; t++) {
ll ways = C(len, t) * C(sum + len - 1 - t * step, len - 1) % MOD;
if (t & 1) ans = (ans - ways + MOD) % MOD;
else ans = (ans + ways) % MOD;
}
return ans;
}
int main() {
setIO();
initComb();
int T;
cin >> T;
while (T--) {
int n, m;
cin >> n >> m;
ll invNMinus1 = modPow(n - 1, MOD - 2);
ll ans = 0;
for (int x = 0; x <= m; x++) {
ll g1 = boundedCount(n - 1, m - x, x);
ll g2 = boundedCount(n - 2, m - 2 * x, x);
ans = (ans + 1LL * x * g1) % MOD;
ans = (ans + 1LL * x * (n - 1) % MOD * g2) % MOD;
ll bad = 0;
bad = (bad + 1LL * (m - x) * g1 % MOD * invNMinus1) % MOD;
bad = (bad + 1LL * x * g2) % MOD;
bad = (bad + (1LL * (m - 2 * x) % MOD + MOD) % MOD * g2) % MOD;
ans = (ans - bad + MOD) % MOD;
}
cout << ans << '\n';
}
}#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int MOD = 1000000007;
const int MAXF = 400005;
ll fact[MAXF], invFact[MAXF];
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
ll modPow(ll a, ll e) {
ll r = 1;
while (e) {
if (e & 1) r = r * a % MOD;
a = a * a % MOD;
e >>= 1;
}
return r;
}
void initComb() {
fact[0] = 1;
for (int i = 1; i < MAXF; i++) fact[i] = fact[i - 1] * i % MOD;
invFact[MAXF - 1] = modPow(fact[MAXF - 1], MOD - 2);
for (int i = MAXF - 1; i > 0; i--) invFact[i - 1] = invFact[i] * i % MOD;
}
ll C(int n, int r) {
if (n < 0 || r < 0 || r > n) return 0;
return fact[n] * invFact[r] % MOD * invFact[n - r] % MOD;
}
ll boundedCount(int len, int sum, int mx) {
if (sum < 0) return 0;
if (len == 0) return sum == 0;
ll ans = 0;
int step = mx + 1;
for (int t = 0; t <= len && 1LL * t * step <= sum; t++) {
ll ways = C(len, t) * C(sum + len - 1 - t * step, len - 1) % MOD;
if (t & 1) ans = (ans - ways + MOD) % MOD;
else ans = (ans + ways) % MOD;
}
return ans;
}
int main() {
setIO();
initComb();
int T;
cin >> T;
while (T--) {
int n, m;
cin >> n >> m;
ll invNMinus1 = modPow(n - 1, MOD - 2);
ll ans = 0;
for (int x = 0; x <= m; x++) {
ll g1 = boundedCount(n - 1, m - x, x);
ll g2 = boundedCount(n - 2, m - 2 * x, x);
ans = (ans + 1LL * x * g1) % MOD;
ans = (ans + 1LL * x * (n - 1) % MOD * g2) % MOD;
ll bad = 0;
bad = (bad + 1LL * (m - x) * g1 % MOD * invNMinus1) % MOD;
bad = (bad + 1LL * x * g2) % MOD;
bad = (bad + (1LL * (m - 2 * x) % MOD + MOD) % MOD * g2) % MOD;
ans = (ans - bad + MOD) % MOD;
}
cout << ans << '\n';
}
}