1. 程式人生 > 其它 >【題解】ARC124E - Pass to Next

【題解】ARC124E - Pass to Next

首先我們要求集合中所有方案的代價之和,簡單分析下不難發現,如果每個位置都傳球了,那麼每個位置都少傳一個球的方案一定會被重複統計。

所以答案就是總方案數減去每個位置都至少傳一個球的方案數。

考慮 \(\prod x_i\) 的意義,等價於傳球后從每個人手中拿出一個球的方案數。

因此我們將每個人的球排成一排,顯然對於每個人來說,他可以選擇拿出自己的球,也可以從前面一個人中拿出一個球。需要注意的是自己拿的球一定在前面一個人後面,並且兩人之間存在一個斷點。

所以我們定義狀態 \(f_{i,0/1}\) 表示前 \(i\) 個人,第 \(i\) 個人拿自己/別人的球,前 \((i - 1)\) 個人的方案數。每次欽定 \(f_{1,0/1}\)

中的一個為 \(1\),另一個為 \(0\),求出對應的 \(f_{n + 1,0/1}\) 就是答案。每個人都要傳球的轉移類似。

這就是計數的第X種方法——組合意義

#define N 300005
int n, a[N], f[N][2];
int g2(int x){
	return 1LL * x * (x - 1) % P * ((P + 1) / 2) % P;
}
int g3(int x){
	return 1LL * x * (x - 1) % P * (x - 2) % P * ((P + 1) / 6) % P;
}
int w2(int x){
	return (g2(x) + x) % P;
}
int w3(int x){
	return (g3(x) + g2(x)) % P;
}
int calc(int st, int op){
	memset(f, 0, sizeof(f));
	if(!op){
		f[1][st] = 1;
		rep(i, 1, n){
			if(a[i] > 0)ad(f[i + 1][0], 1LL * f[i][1] * (a[i] + 1) % P);
			if(a[i] > 0)ad(f[i + 1][0], 1LL * f[i][0] * w2(a[i]) % P);
			if(a[i] > 0)ad(f[i + 1][1], 1LL * f[i][1] * w2(a[i]) % P);
			if(a[i] > 1)ad(f[i + 1][1], 1LL * f[i][0] * w3(a[i]) % P);
		}
		return f[n + 1][st];
	}
	f[1][st] = 1;
	rep(i, 1, n){
		if(a[i] > 0)ad(f[i + 1][0], 1LL * f[i][1] * a[i] % P);
		if(a[i] > 0)ad(f[i + 1][0], 1LL * f[i][0] * g2(a[i]) % P);
		if(a[i] > 0)ad(f[i + 1][1], 1LL * f[i][1] * w2(a[i]) % P);
		if(a[i] > 1)ad(f[i + 1][1], 1LL * f[i][0] * w3(a[i]) % P);
	}
	return f[n + 1][st];
}
int main() {
	//int T = read();while(T--)solve();
	n = read();
	rp(i, n)
		a[i] = read();
	//cout << w3(3) << " " << w3(4) << endl;
	//cout << g3(2) << " " << g3(3) << " " << g3(4) << endl;
	int ans = (calc(0, 0) + calc(1, 0)) % P;
	su(ans, (calc(0, 1) + calc(1, 1)) % P);
	cout << ans << endl;
	return 0;
}