题目链接

LOJ 2552

Luogu P4564

考场上这道题我先是写了个70分暴力,然后发现似乎可以NTT,然鹅问题是——我没学过NTT,遂脑补之,脑补出来了,下午出成绩一看,卡成暴力分(70)……同是\(O(Qk^2\log k)\),学姐的拉格朗日什么玩意就能过TAT……学姐太强了……

遂不忿,今天上午重写NTT,努力卡常,卡不进去……

那还是写正解吧。

首先,发现血量上限很少,0操作时,暴力维护每一时刻每个人是每种血量大小的概率即可。

1操作怎么办呢?设\(alive_i\)是\(i\)号人活着的概率,\(dead_i\)是他死了的概率,\(g_{i,j}\)是除\(i\)以外活了\(j\)个人的概率,\(i\)号人的答案就是$$alive_i * \sum_{j = 0}^{k - 1}\frac{1}{j + 1} * g_{i,j}$$

但是\(g_{i,j}\)怎么求呢?发现可以DP:设\(f_{i,j}\)表示前\(i\)个人有\(j\)个活着的概率,则$$f_{ij} = f_{i-1,j} * dead_i + f_{i-1,j-1} * alive_i$$

注意到最后的\(f\)和人的顺序无关,所以可以把人的顺序任意调换,把要求的这个\(i\)放在最后一个,这样\(f_{k - 1}\)就是\(g_{i}\)。

那么对于每个\(i\)求一遍\(f\),复杂度是\(O(n^3)\)的,能得70分。

如何优化呢?考虑把\(i\)号人放在最后时,从\(f_k\)倒推到\(f_{k-1}\):$$\frac{f_{k-1, j} = f_{k, j} - f_{k -1, j - 1} * alive_i}{dead_i}$$

注意到\(dead_i = 0\)时该式不能用,又发现此时\(f_{k-1, j} = f_{k, j+1}\),所以也能直接求。

那么\(O(n^2)\)求出\(f_k\),再\(O(n^2)\)倒推,直接可以获得答案!

#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <iostream>
#define space putchar(' ')
#define enter putchar('\n')
typedef long long ll;
using namespace std;
template <class T>
void read(T &x){
char c;
bool op = 0;
while(c = getchar(), c < '0' || c > '9')
if(c == '-') op = 1;
x = c - '0';
while(c = getchar(), c >= '0' && c <= '9')
x = x * 10 + c - '0';
if(op) x = -x;
}
template <class T>
void write(T x){
if(x < 0) putchar('-'), x = -x;
if(x >= 10) write(x / 10);
putchar('0' + x % 10);
} const int N = 256, P = 998244353;
int n, m, K, t[N], b[N], rate[N][105], iv[N];
ll qpow(ll a, ll x){
ll ret = 1;
while(x){
if(x & 1) ret = ret * a % P;
a = a * a % P;
x >>= 1;
}
return ret;
}
void attack(int tar, ll x){
ll y = (1 - x + P) % P;
for(int i = 0; i <= b[tar]; i++){
if(i) rate[tar][i] = rate[tar][i] * y % P;
if(i < b[tar]) rate[tar][i] = (rate[tar][i] + rate[tar][i + 1] * x) % P;
}
}
void query(){
static ll f[N], g[N], h[N];
memset(f, 0, sizeof(f));
f[0] = 1;
for(int i = 1; i <= K; i++)
for(int j = i; j >= 0; j--)
f[j] = ((j ? f[j - 1] * (1 - rate[t[i]][0]) : 0) + f[j] * rate[t[i]][0]) % P;
for(int i = 1; i <= K; i++){
h[i] = 0;
if(!rate[t[i]][0])
for(int j = 0; j < K; j++)
h[i] += f[j + 1] * iv[j + 1] % P;
else{
int inv = qpow(rate[t[i]][0], P - 2);
for(int j = 0; j < K; j++){
g[j] = (f[j] - (j ? g[j - 1] * (1 - rate[t[i]][0]) : 0)) % P * inv % P;
h[i] += iv[j + 1] * g[j] % P;
}
}
h[i] %= P;
h[i] = h[i] * (1 - rate[t[i]][0]) % P;
if(h[i] < 0) h[i] += P;
}
for(int i = 1; i <= K; i++)
write(h[i]), i == K ? enter: space;
} int main(){ read(n);
for(int i = 1; i <= n; i++)
read(b[i]), rate[i][b[i]] = 1, iv[i] = qpow(i, P - 2);
read(m);
int op, x, u, v;
while(m--){
read(op);
if(op == 0) read(x), read(u), read(v), attack(x, u * qpow(v, P - 2) % P);
else{
read(K);
for(int i = 1; i <= K; i++) read(t[i]);
query();
}
}
for(int i = 1; i <= n; i++){
ll sum = 0;
for(int j = 1; j <= b[i]; j++)
sum += (ll)j * rate[i][j] % P;
write(sum % P), i == n ? enter: space;
} return 0;
}

[CTSC2018] 假面 | 期望 DP的更多相关文章

  1. UOJ399 CTSC2018 假面 期望、DP

    传送门 \(Q \leq 200000 , C \leq 1000 , m_i \leq 100\)-- 先考虑如何维护最后一次操作时所有人的血量期望.不难发现我们需要的复杂度是\(O(Qm_i)\) ...

  2. [CTSC2018]假面(概率DP)

    考场上以为CTSC的概率期望题都不可做,连暴力都没写直接爆零. 结果出来发现全场70以上,大部分AC,少于70的好像极少,感觉血亏. 设a[i][j]表示到当前为止第i个人的血量为j的概率(注意特判血 ...

  3. 【BZOJ-1419】Red is good 概率期望DP

    1419: Red is good Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 660  Solved: 257[Submit][Status][Di ...

  4. [NOIP2016]换教室 D1 T3 Floyed+期望DP

    [NOIP2016]换教室 D1 T3 Description 对于刚上大学的牛牛来说, 他面临的第一个问题是如何根据实际情况中情合适的课程. 在可以选择的课程中,有2n节课程安排在n个时间段上.在第 ...

  5. HDU 4336 Card Collector (期望DP+状态压缩 或者 状态压缩+容斥)

    题意:有N(1<=N<=20)张卡片,每包中含有这些卡片的概率,每包至多一张卡片,可能没有卡片.求需要买多少包才能拿到所以的N张卡片,求次数的期望. 析:期望DP,是很容易看出来的,然后由 ...

  6. 【BZOJ-4008】亚瑟王 概率与期望 + DP

    4008: [HNOI2015]亚瑟王 Time Limit: 20 Sec  Memory Limit: 512 MBSec  Special JudgeSubmit: 832  Solved: 5 ...

  7. 期望dp BZOJ3450+BZOJ4318

    BZOJ3450 概率期望DP f[i]表示到i的期望得分,g[i]表示到i的期望长度. 分三种情况转移: ① s[i]=‘x’:f[i]=f[i-1],g[i]=0 ② s[i]=‘o’:f[i]= ...

  8. HDU 4405 期望DP

    期望DP算是第一题吧...虽然巨水但把思路理理清楚总是好的.. 题意:在一个1×n的格子上掷色子,从0点出发,掷了多少前进几步,同时有些格点直接相连,即若a,b相连,当落到a点时直接飞向b点.求走到n ...

  9. POJ 2096 【期望DP】

    题意: 有n种选择,每种选择对应m种状态.每种选择发生的概率相等,每种选择中对应的每种状态发生的概率相等. 求n种选择和m种状态中每种至少发生一次的期望. 期望DP好别扭啊.要用倒推的方法. dp[i ...

随机推荐

  1. Intel x86_64 Architecture Background 2

    这里是在学习Intel x86_64体系架构时学习到的一些概念,记录下来以供日后参考.如果有错的地方,欢迎指正! CPU上下文切换(context switch): 这个概念第一次听到对我来说是完全陌 ...

  2. 以英雄联盟的方式建模,谈对依赖注入(DI)的理解以及Autofac的用法(一)

    一.前言 近期在探索分层架构和架构设计,选择了领域驱动作为5年.Net开发后的新的方向,不可避免的接触了IoC/DI方面的技术.目前通过反射或其他方法都已实现,但只知其一,并没有考虑为什么要这么做,同 ...

  3. C/C++中连接函数strcat的应用(简单讲解)

    有位学弟问到我如何将两个字符连接起来,想想java/python里面可以直接用+连接起来,可是C/C++里面有没有这么方便的做法呢? 答案是有的,在C语言的string.h库中有个神奇的函数叫做str ...

  4. Microsoft Office软件自定义安装目录

    Microsoft Office安装时不能手动设置安装目录,本文描述通过修改注册表的方式自定义安装目录 1.同时按下快捷键 win + r 启动运行 2.输入 regedit 打开注册表 3.找到   ...

  5. Linux下针对服务器网卡流量和磁盘的监控脚本

    1)实时监控网卡流量的通用脚本: [root@ceph-node1 ~]# cat /root/net_monit.sh #!/bin/bash PATH=/bin:/usr/bin:/sbin:/u ...

  6. ul ol li的序号编号样式

    序号样式例子,下面是html代码(做参考) <ol> <li>列表内容列表内容列表内容列表</li> <li>列表内容列表内容列表内容列表</li ...

  7. Python基础系列讲解——random模块随机数的生成

    随机数参与的应用场景大家一定不会陌生,比如密码加盐时会在原密码上关联一串随机数,蒙特卡洛算法会通过随机数采样等等.Python内置的random模块提供了生成随机数的方法,使用这些方法时需要导入ran ...

  8. B. Interesting drink

    链接 [http://codeforces.com/group/1EzrFFyOc0/contest/706/problem/B] 题意 给你n个数,q次查询,每次输入一个m,问n个数中有多少个数小于 ...

  9. Python学习笔记——Python Number(数字)

    Python Number 类型转换 int(x, y) #将x转换为一个整数,y为进制数.如 int('11',2)将二进制数的11转成十进制数的整数,结果为3 long(x, y) #将x转换为一 ...

  10. PAT 甲级 1045 Favorite Color Stripe

    https://pintia.cn/problem-sets/994805342720868352/problems/994805437411475456 Eva is trying to make ...