トピックポータル:LOJの#3160。
簡単に言えば質問の意味:
長有する(\ N-)\のシーケンス\(A \) 、初期\(a_iを= iは\)または\(= a_iをI ^ 2 \) 、依存\(\ mathrm {タイプ} \ ) の値。
このシーケンス\(m個\)操作、各操作が値所与\(a_iを\)は、この配列は、2つの部分に分割される:([1:a_iを] \)\と\([a_iを+ 。1:N-] \) 、内部配列を対向両者の順序を変更することなく、次に限界、2つの配列は一様に新しいシーケンスを形成するために混合される、新しいシーケンス\(\)は、の混合物であります新しいシーケンス。
\(Q \)このクエリの後に時間\(m個\)操作の後、特定の位置の値\(A_ {C_I} \)の所望。
ソリューション:
それは均一に混合ので、すべてであるため、\(\ displaystyle binom {N} {a_iを} \ \) の混合物、すべての方法の発生確率は等しいです。
最初する(\ 30 \)分\(\ mathcal {O}( M \のCDOT N ^ 2)\) 暴力を、それが試料又は観察に見出すことができる:操作は、任意の回数、配列行った後\(\ mathbbを{ Eは} [a_iを] \)静止関数又は二次関数です。
この結論はとても感情的に理解することができます:
- まず、最初の関数は二次関数であるか、単に変わらないままに操作の数の後に一次関数や二次関数を証明します。
- 検討(\ mathbb {E} [a_iを] = F(I)\)\ここで、\(F(x)が\)約ある\(X \)線形関数又は二次関数です。
- 所与の値の後に\(K \)操作の後、左セクション\(Iは\)という用語は、に等しい\(F(I)\)の右辺\(Iは\)という用語は、に等しい\(F(K私は\))+、双方が機能の数が同じです。
- 数が減少しないように、2つの線形関数又は均一混合の機能に対応する形状の二次関数の配列は、数が増加されるべきではなく、同じ符号最上位の係数から、最上位の項はキャンセルされません。
ちょうどその最初の3つの値のそれぞれは、最初の三つは、(得られた)最初の3つのシーケンスによって残されてもよいし、得ることができ、最初の3つの配列の右プッシュ限り、組み合わせ(得られた補間を必要とします)いくつかの簡単な式は次の3つの新しい前の値を見つけることができます。
以下は、コードの複雑さである\(\ mathcal {O}(M)\) 。
#include <cstdio>
typedef long long LL;
const int Mod = 998244353;
const int Inv2 = (Mod + 1) / 2;
inline int qPow(int b, int e) {
int a = 1;
for (; e; e >>= 1, b = (LL)b * b % Mod)
if (e & 1) a = (LL)a * b % Mod;
return a;
}
inline int gInv(int x) { return qPow(x, Mod - 2); }
int N, M, A, Q, Typ;
LL iN0, iN1, iN2;
int E1, E2, E3;
inline int GetX(int i) {
if (i == 1) return E1;
if (i == 2) return E2;
if (i == 3) return E3;
int SE1 = (LL)E1 * (i - 2) % Mod * (i - 3) % Mod;
int SE2 = (LL)E2 * (2 - i - i + Mod) % Mod * (i - 3) % Mod;
int SE3 = (LL)E3 * (i - 1) % Mod * (i - 2) % Mod;
return ((LL)SE1 + SE2 + SE3) * Inv2 % Mod;
}
int main() {
freopen("landlords.in", "r", stdin);
freopen("landlords.out", "w", stdout);
scanf("%d%d%d", &N, &M, &Typ), --Typ;
iN0 = gInv(N), iN1 = gInv((LL)N * (N - 1) % Mod), iN2 = gInv((LL)N * (N - 1) % Mod * (N - 2) % Mod);
E1 = 1, E2 = Typ ? 4 : 2, E3 = Typ ? 9 : 3;
while (M--) {
scanf("%d", &A);
LL F1 = E1, F2 = E2, F3 = E3;
LL F4 = GetX(A + 1), F5 = GetX(A + 2), F6 = GetX(A + 3);
E1 = (F1 * A + F4 * (N - A)) % Mod * iN0 % Mod;
E2 = (F2 * A % Mod * (A - 1) + (F1 + F4) * A % Mod * (N - A) + F5 * (N - A) % Mod * (N - A - 1)) % Mod * iN1 % Mod;
E3 = (F3 * A % Mod * (A - 1) % Mod * (A - 2) + (F4 + F2 + F2) * A % Mod * (A - 1) % Mod * (N - A) + (F5 + F5 + F1) * A % Mod * (N - A) % Mod * (N - A - 1) % Mod + F6 * (N - A) % Mod * (N - A - 1) % Mod * (N - A - 2)) % Mod * iN2 % Mod;
}
scanf("%d", &Q);
for (int X; Q--; ) {
scanf("%d", &X);
printf("%d\n", GetX(X));
}
return 0;
}