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.
Do not simulate sequences of attractions. The final array always stays nondecreasing, so it is completely determined by the counts number of people standing at coordinate .
Not every nondecreasing array works. The useful invariant is about occupied coordinates: the positive values must form one contiguous interval. No holes allowed.
Now look at parity. If a coordinate is strictly inside the occupied interval, its count must be odd. An attraction at merges the groups at into one group, so interior groups are built by odd-size merges.
Those two conditions are also sufficient: choose any interval , make endpoint counts positive with any parity, make all interior counts positive odd, and you can construct it by edge pair-merges and interior triple-merges, then translate the block. So yeah, the movement drama becomes stars and bars.
For fixed interval length , all endpoint coordinates have the same total coefficient, and all interior coordinates have the same total coefficient. Write interiors as and endpoints as , with . Then use and the identity that one variable contributes in total over all solutions.
Let be the number of people that finish at coordinate .
Since people never swap order, a final position array is uniquely determined by the count array
If , that just means three consecutive people stand at coordinate . There is no hidden permutation choice.
Reachable Count Arrays
The key characterization is:
A count array is reachable iff:
The endpoints and only need to be positive. Their parity can be anything.
Why this is necessary:
Adjacent people start at distance . Under an attraction, an adjacent gap can decrease, but it never increases. So final adjacent gaps are only or , meaning occupied coordinates cannot have holes.
Now compress people standing at the same coordinate into groups. Initially every group has size . An attraction at an interior coordinate merges the groups at , , and into one group. That is a merge of three groups. Starting from odd groups, a triple merge keeps the size odd. Only boundary groups can be made by pair merges, so only the two endpoints can have arbitrary parity.
Why this is sufficient:
Take any desired interval and counts satisfying those conditions. Think in terms of consecutive groups of original people. The left endpoint group can be made by repeatedly attracting at the left edge, merging one more group into it each time. Same for the right endpoint. Every interior target count is odd, so that block can be reduced to one group by repeatedly merging triples inside it. After all groups are built, the whole occupied block can be shifted left or right by attracting at or . So the characterization is exact.
Now the problem is pure counting. Nice. The physics has left the building.
One Fixed Interval Length
Fix the occupied interval length
For , all people stand at one coordinate, so every coordinate contributes once.
Now assume . For one fixed interval, write its counts as
where , and are positive odd.
Encode the endpoint parities with
where . For every interior coordinate,
There are interior coordinates, so after subtracting the fixed parts we need
where
If is not a nonnegative integer, this parity choice gives nothing.
Otherwise, the number of solutions is
Across all solutions, the total contribution of one chosen variable is
This is the standard stars-and-bars marked-unit identity.
So for this fixed :
After summing over all four choices of , define:
For interval , its contribution is
Summing All Intervals Fast
For fixed , let
be the sum of all endpoints, and let
be the sum of all length- interval sums.
Then the total for this is
is just a prefix plus a suffix:
For , use prefix sums :
This becomes
so a prefix sum over the array gives in .
Precompute factorials and inverse factorials for binomial coefficients. Each is handled in , so each test case is , and the total input size is .
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const ll MOD = 998244353;
const int MAXN = 200000;
vector<ll> fact, invfact;
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;
}
ll C(int n, int k) {
if (n < 0 || k < 0 || k > n) return 0;
return fact[n] * invfact[k] % MOD * invfact[n - k] % MOD;
}
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
int main() {
setIO();
fact.assign(MAXN + 1, 1);
invfact.assign(MAXN + 1, 1);
for (int i = 1; i <= MAXN; i++) fact[i] = fact[i - 1] * i % MOD;
invfact[MAXN] = modpow(fact[MAXN], MOD - 2);
for (int i = MAXN; i >= 1; i--) invfact[i - 1] = invfact[i] * i % MOD;
int tc;
cin >> tc;
while (tc--) {
int n;
cin >> n;
vector<ll> a(n + 1), pref(n + 1), ppref(n + 1);
for (int i = 1; i <= n; i++) {
cin >> a[i];
a[i] %= MOD;
pref[i] = (pref[i - 1] + a[i]) % MOD;
}
for (int i = 1; i <= n; i++) {
ppref[i] = (ppref[i - 1] + pref[i]) % MOD;
}
auto sumPref = [&](int l, int r) -> ll {
if (l > r) return 0;
return (ppref[r] - (l ? ppref[l - 1] : 0) + MOD) % MOD;
};
ll ans = 1LL * n * pref[n] % MOD;
for (int K = 2; K <= n; K++) {
ll edge = 0, mid = 0;
for (int x = 1; x <= 2; x++) {
for (int y = 1; y <= 2; y++) {
int rem = n - x - y - (K - 2);
if (rem < 0 || (rem & 1)) continue;
int T = rem / 2;
ll ways = C(T + K - 1, K - 1);
ll sumG = C(T + K - 1, K);
edge = (edge + 2 * sumG + x * ways) % MOD;
mid = (mid + 2 * sumG + ways) % MOD;
}
}
int cnt = n - K + 1;
ll totalIntervals = (sumPref(K, n) - sumPref(0, n - K) + MOD) % MOD;
ll endpointSum = (pref[cnt] + pref[n] - pref[K - 1] + MOD) % MOD;
ll interiorSum = (totalIntervals - endpointSum + MOD) % MOD;
ans = (ans + edge * endpointSum + mid * interiorSum) % MOD;
}
cout << ans << '\n';
}
return 0;
}#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const ll MOD = 998244353;
const int MAXN = 200000;
vector<ll> fact, invfact;
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;
}
ll C(int n, int k) {
if (n < 0 || k < 0 || k > n) return 0;
return fact[n] * invfact[k] % MOD * invfact[n - k] % MOD;
}
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
int main() {
setIO();
fact.assign(MAXN + 1, 1);
invfact.assign(MAXN + 1, 1);
for (int i = 1; i <= MAXN; i++) fact[i] = fact[i - 1] * i % MOD;
invfact[MAXN] = modpow(fact[MAXN], MOD - 2);
for (int i = MAXN; i >= 1; i--) invfact[i - 1] = invfact[i] * i % MOD;
int tc;
cin >> tc;
while (tc--) {
int n;
cin >> n;
vector<ll> a(n + 1), pref(n + 1), ppref(n + 1);
for (int i = 1; i <= n; i++) {
cin >> a[i];
a[i] %= MOD;
pref[i] = (pref[i - 1] + a[i]) % MOD;
}
for (int i = 1; i <= n; i++) {
ppref[i] = (ppref[i - 1] + pref[i]) % MOD;
}
auto sumPref = [&](int l, int r) -> ll {
if (l > r) return 0;
return (ppref[r] - (l ? ppref[l - 1] : 0) + MOD) % MOD;
};
ll ans = 1LL * n * pref[n] % MOD;
for (int K = 2; K <= n; K++) {
ll edge = 0, mid = 0;
for (int x = 1; x <= 2; x++) {
for (int y = 1; y <= 2; y++) {
int rem = n - x - y - (K - 2);
if (rem < 0 || (rem & 1)) continue;
int T = rem / 2;
ll ways = C(T + K - 1, K - 1);
ll sumG = C(T + K - 1, K);
edge = (edge + 2 * sumG + x * ways) % MOD;
mid = (mid + 2 * sumG + ways) % MOD;
}
}
int cnt = n - K + 1;
ll totalIntervals = (sumPref(K, n) - sumPref(0, n - K) + MOD) % MOD;
ll endpointSum = (pref[cnt] + pref[n] - pref[K - 1] + MOD) % MOD;
ll interiorSum = (totalIntervals - endpointSum + MOD) % MOD;
ans = (ans + edge * endpointSum + mid * interiorSum) % MOD;
}
cout << ans << '\n';
}
return 0;
}