Loading

【题解】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;
}
posted @ 2021-10-01 15:33  7KByte  阅读(136)  评论(0编辑  收藏  举报