[ARC120F] Wine Thief(F)

\(\text{Solution}\)

一道思维题,我们发现计算答案肯定是考虑每一个数\(a_i\)的贡献,但我们发现其系数不好算。如果是在一个环上,那么每个位置的系数是相同的,而且很好计算。设\(f_{i,j}\)表示在长度为\(i\)的序列上选\(j\)个不相邻的点,显然\(f_{i,j} = \dbinom{i - j + 1}{j}\),那么一个长为\(n\)的环上选\(k\)个点的答案为\(\sum a_if_{n - 3,k - 1}\)
还原到序列上,我们会少算\(1\)\(n\)都选的答案,那么加上即可。设\(g_{l,r,k}\)表示序列\(l - r\)\(k\)个点的答案,那么

\[g_{l,r,k} = \sum a_if_{(r - l + 1) - 3,k - 1} + f_{(r - l + 1) - 4, k - 2} *(a_l + a_r) + g_{l + 2, r - 2, k - 2} \]

这样就可以求出\(g_{1, n, k}\),时间复杂度为\(O(n)\)

$\text{Code}$
#include<cstdio>
#include<iostream>
#define IN inline
#define LL long long
using namespace std;
const int N = 3e5 + 5, P = 998244353;
int n, K, D; LL a[N], s[N], fac[N], inv[N];

IN int read() {
	int res = 0; char ch = getchar();
	for (; !isdigit(ch); ch = getchar());
	for (; isdigit(ch); ch = getchar()) res = (res << 3) + (res << 1) + (ch ^ 48);
	return res;
}
LL getf(int x, int y) {
	if (x - y + 1 < y || y < 0) return 0;
	return fac[x - y + 1] * inv[y] % P * inv[x - 2 * y + 1] % P;
}
LL solve(int l, int r, int k) {
	if (k <= 0) return 0LL;
	if (k == 1) return s[r] - s[l - 1];
	LL res = getf(r - l - 2, k - 1) * (s[r] - s[l - 1] + P) % P;
	(res += getf(r - l - 3, k - 2) * (a[r] + a[l]) % P + solve(l + 2, r - 2, k - 2)) %= P;
	return res;
}
int main() {
	n = read(), K = read(), D = read(), fac[0] = inv[1] = inv[0] = 1;
	for (int i = 1; i <= n; i++) fac[i] = fac[i - 1] * (LL)i % P;
	for (int i = 2; i <= n; i++) inv[i] = (LL)(P - P / i) * inv[P % i] % P;
	for (int i = 2; i <= n; i++) inv[i] = inv[i] * inv[i - 1] % P;
	for (int i = 1; i <= n; i++) a[i] = read(), s[i] = (s[i - 1] + a[i]) % P;
	printf("%lld\n", solve(1, n, K));
}

posted @ 2022-11-15 19:41  RiverSheep  阅读(39)  评论(0)    收藏  举报