ARC124E

传出球的最小值不为 0 时,可以将所有人传出球的数量同时减一,得到的序列不变。
所以得出结论,所有人传出的球的数量的最小值必定为 0
观察答案的实际含义:最终序列中从每个人手上选出一个球的方案数。
每个人的球只有两种来源:自己原来没有传出去的球/上一个人传过来的球。启示我们记录球的来源以 DP。
状态的定义有点奇怪:fi,0 表示第 i 个人从自己处选择球且不计第 i 个人选择方案时前 i1 个人的选球方案数,fi,1 表示第 i 个人从前面人选择球且计入第 i 个人的选球方案时的方案数。
转移分为四种情况:
(i,0)(i+1,0),此时要计算第 i 个人的选择方案,剩下几个球就有几种转移方案,转移系数为 aik=1k
(i,0)(i+1,1),此时要计算第 i 个人和第 i+1 个人的选择方案,转移系数为 ai1k=1k×(aik)
(i,1)(i+1,0),此时要计算第 i 个人的传球方案,转移系数为送出几个球,即 aik=01=ai+1
(i,1)(i+1,1),此时要计算第 i+1 个人的选择方案,转移系数为 aik=1k
因为是一个环,那么可以枚举 1 的决策然后开始 DP。
注意这样子统计出来的并不要求传球数最小为 0 那么可以再编一个传球数最小为 1 的式子写出来即可。

Code:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 100005, mod = 998244353, inv2 = (mod + 1) / 2, inv6 = (mod + 1) / 6;
int n;
int a[N], f[N][2];

void add(int &a, int b) {
	a += b;
	if (a >= mod) a -= mod;
	if (a < 0) a += mod;
}

int calc1(int x) { return 1ll * x * (x + 1) % mod * inv2 % mod; }
int calc2(int x) { return 1ll * x * (x + 1) % mod * (2 * x + 1) % mod * inv6 % mod; }

int solve(int x, int y) {
	memset(f, 0, sizeof f);
	f[1][x] = 1;
	for (int i = 1; i <= n; ++i) {
		add(f[i + 1][0], 1ll * f[i][0] * calc1(a[i] - y) % mod), add(f[i + 1][0], 1ll * f[i][1] * (a[i] - y + 1) % mod);
		add(f[i + 1][1], 1ll * f[i][0] * ((1ll * a[i] * calc1(a[i]) % mod - calc2(a[i]) + mod) % mod) % mod), add(f[i + 1][1], 1ll * f[i][1] * calc1(a[i]) % mod);
	}
	return f[n + 1][x];
}

int main() {
	scanf("%d", &n);
	for (int i = 1; i <= n; ++i) scanf("%d", &a[i]);
	int ans = 0; add(ans, solve(1, 0)), add(ans, solve(0, 0));
	add(ans, -solve(1, 1)), add(ans, -solve(0, 1));
	printf("%d", ans);
	return 0;
}
posted @   Kobe303  阅读(33)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话
点击右上角即可分享
微信分享提示