[HNOI2015]亚瑟王
(看到题解里面有一篇和我最初想法挺像但好像不是大众解法的题解,有点激动,干脆自己也来写篇题解好了)
Description#
你有
-
如果这张卡片在之前被发动过,直接跳过;
-
如果当前卡片发动了,产生
的贡献并直接开始下一轮; -
否则没有发动的话,换到下一张卡片。
求期望获得贡献。
多测。
Analysis#
注意到题目暗含的意思应该是玩多少轮游戏,就会发动多少次卡片。(具体哪张并不清楚)
根据期望的线性性质,我们可以单独考虑每个点发动的概率
所以在可以不考虑第几轮的情况下,我们可以这样设一个 DP 状态:
Solution#
因为每张卡片发动一次之后就不能再发动了,发动之后的卡片视作概率为
假设第
-
对于之后的轮次,概率为
,可以拆成发动 不发动两种情况; -
而对于前面的轮次,概率一致,属于同类项。
如此来看的话原先定义的
会不会算重呢?假如如果第
那就有
问题解决了一半。
还有一个问题,我们还是被每轮只能发动一次这个条件限制的死死的:因为前者的发动概率会直接影响后面的卡片发动概率,所以同时要算当前状态的概率以及期望。
我们就可以理解为每张卡片在它后面的每张卡片上叠了 buff 。
(不知道怎么的)猛然间想起期望入门的时候做过的这道题
前者影响后者,那就正难则反!!全部逆推,反正后面的卡片都要被前面影响,该叠 buff 就正常叠就行了。
所以就有很自然的 DP 方程式啦(注意是逆推啦):
分别的两个系数就是上文讲的发动或者不发动。
(常熟还小/hanx)
Code#
Code
/*
*/
#include
using namespace std;
typedef long long ll;
const int N = 222;
int n, r, d[N];
double p[N], f[N][N];
inline int read() {
char ch = getchar();
int s = 0, w = 1;
while (!isdigit(ch)) {if (ch == '-') w = -1; ch = getchar();}
while (isdigit(ch)) {s = (s << 3) + (s << 1) + (ch ^ 48); ch = getchar();}
return s * w;
}
inline double dead() {
char ch = getchar();
ll s = 0, w = 1, k = 0;
double m = 1; bool is = 0;
while (!isdigit(ch)) {if (ch == '-') w = -1; ch = getchar();}
while (isdigit(ch) || ch == '.') {
if (ch == '.') is = 1;
else if (!is) s = (s << 3) + (s << 1) + (ch ^ 48);
else k = (k << 3) + (k << 1) + (ch ^ 48), m *= 0.1;
ch = getchar();
}
return (m * k + s) * w;
}
inline void mian() {
memset(f, 0, sizeof(f));
n = read(); r = read();
for (int i = 1; i <= n; ++i) p[i] = dead(), d[i] = read();
for (int i = n; i >= 1; --i) {
double P = 1.0 - p[i];
for (int j = 1; j <= r; ++j) {
f[i][j] = f[i + 1][j] * P + (f[i + 1][j - 1] + d[i]) * (1.0 - P);
P *= 1.0 - p[i];
}
}
printf("%.9lf\n", f[1][r]);
}
int main() {
int T = read();
while (T--) mian();
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?