题解:P5011 水の造题

节选自:DP做题记录(三)(2025.4.5 - 2025.4.19)

其实这道题目的样例解释已经把如何统计答案讲解的差不多了。

我们考虑 DP,设 \(dp_{i, j}\) 表示这是第 \(i\) 个动作,且第 \(i\) 个动作是 \(j\) 的期望。根据样例解释,我们可以先将期望改写成总和,那么 \(dp_{i, j}\) 的含义就变成了这是第 \(i\) 个动作,且第 \(i\) 个动作是 \(j\) 的威力和。我们再设 \(ans_i\) 表示填完前 \(i\) 个数的威力和,显然 \(ans_i = \displaystyle\sum dp_{i, j}\),而答案就是 \(\displaystyle\frac{1}{k^n} ans_n\)

我们枚举前一个字符 \(c\) 是什么,如果 \(c\) 不等于 \(j - 1\)(当然 \(c = k\) 时是 \(1\)),那么直接加上当前的威力值即可,因此 \(dp_{i, j}\) 首先要加上一个 \(\displaystyle\sum_{c \neq j - 1} dp_{i - 1, c} + a_j\)

下面来考虑威力值的加成,那么前一个填的数字必须是 \(j - 1\),那么 \(dp_{i, j}\) 还要加上一个 \(dp_{i - 1, j - 1} + 2 a_j + a_{j - 1}\),那么总的转移方程就是 \(dp_{i, j} = \displaystyle\sum_{c \neq j - 1} (dp_{i - 1, c} + a_j) + dp_{i - 1, j - 1} + 2a_j + a_{j - 1} = \sum_c dp_{i - 1, c} + k a_j + a_j + a_{j - 1} = ans_{i - 1} + k a_j + a_j + a_{j - 1}\),那么 \(ans_i = k \times ans_{i - 1} + (2 + k) \times sum\)\(sum\)\(a_1, a_2, \dots, a_k\) 之和),根据等比数列求和公式,\(ans_n\) 最终等于 \(sum \times [n k^{n - 1} + (2n - 2) k^{n - 2}]\),除以 \(k^n\) 后就得到了答案 \(\displaystyle\frac{nk + 2n - 2}{k^2} \times sum\)。边读边取模即可。

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int K = 1e6 + 9, MOD = 19491001;
int read(){
	int x = 0, f = 1;
	char ch = getchar();
	while(!isdigit(ch)){
		if(ch == '-') 
			f = -1;
		ch = getchar();
	}
	while(isdigit(ch)){
		x = ((x << 1) + (x << 3) + (ch ^ 48)) % MOD;
		ch = getchar();
	}
	return x * f;
}
int qpow(int a, int b){
	int res = 1;
	while(b > 0){
		if(b & 1)
			res = res * a % MOD;
		a = a * a % MOD;
		b >>= 1;
	}
	return res;
}
int n, k, sum, a[K];
signed main(){
	n = read();
	k = read();
	for(int i = 1; i <= k; i++){
		scanf("%lld", &a[i]);
		sum = (sum + a[i]) % MOD;
	}
	printf("%lld", sum * (n * (k + 2) % MOD - 2 + MOD) % MOD * qpow(k * k % MOD, MOD - 2) % MOD);
	return 0;
}
posted @ 2025-04-22 17:12  Orange_new  阅读(21)  评论(1)    收藏  举报