题解: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;
}
本文来自博客园,作者:Orange_new,转载请注明原文链接:https://www.cnblogs.com/JPGOJCZX/p/18841186

浙公网安备 33010602011771号