LOJ 3160: 「NOI2019」斗主地


題目傳送門:LOJ #3160

簡要題意:

有一個長度為 \(n\) 的序列 \(a\),初始時 \(a_i=i\)\(a_i=i^2\),這取決於 \(\mathrm{type}\) 的值。

對這個序列進行 \(m\) 次操作,每次操作給定一個值 \(A_i\),把這個序列分為兩部分:\(a[1:A_i]\)\(a[A_i+1:n]\),然后在不改變兩個序列內部相對順序的限制下,均勻地將這兩個序列混合,形成新的序列,則新的序列 \(a\) 即為這個混合而成的新序列。

\(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+i)\),左右兩邊也是次數相同的函數。
  • 兩個一次函數或二次函數形成的序列均勻混合后對應的函數,次數是不應當增加的,而因為最高次項系數符號相同,最高次項也不會被抵消,所以次數也不會減少。

那么每次只需求出前三項的值即可,前三項只有可能由左邊序列的前三項(這已經求出)和右邊序列的前三項(需要插值求出)組合而成,只要推一些簡單的式子就可以求出新的前三項的值了。

以下是代碼,復雜度 \(\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;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM