题意

题目链接

Sol

多年以后,我终于把这题的暴力打出来了qwq 好感动啊。。

刚开始的时候想的是:

设\(f[i][j]\)表示第\(i\)轮, 第\(j\)个人血量的期望值

转移的时候若要淦这个人,那么\(f[i][j] = (f[i - 1][j] + 1) * p + (f[i - 1][j]) * (1 - p)\)

然后发现自己傻逼了。。因为期望不能正着推。

考虑直接推概率,设\(t[k][i][j]\)表示第\(k\)轮,第\(i\)个人,血量为\(j\)的概率

这玩意儿是可以转移的,就是判一下这次打中了没有

第二问可以对每个点分别算答案,设\(g[i][j]\)表示除必须活着的人外,前\(i\)个人中,有\(j\)个活着的概率,背包转移一下

这样复杂度是\(O(qn + n^3)\)的

显然第二问看起来非常暴力,

标算的做法好像叫“退背包”,也就是从背包中删除一个元素

先不考虑某个元素必须存活,推一遍得到\(g[i][j]\)表示前\(i\)个人中,有\(j\)个存活的概率

考虑转移的式子,设\(ali[i]\)表示第\(i\)个人活着的概率

\(g[i][j] = g[i - 1][j - 1] * ali[i] + g[i - 1][j] * (1 - ali[i])\)

而我们要得到的实际上就是\(g[i-1][j]\)这一项

那么\(g[i - 1][j] = \frac{g[i][j] - g[i - 1][j - 1] * ali[i]}{1 - ali[i]}\)

倒着推一遍即可,注意当\(1 - ali[i] = 0\)的时候需要特判,此时\(g[i - 1][j] = g[i][j + 1]\)

70分

#include<bits/stdc++.h>
//#define int long long
using namespace std;
const int MAXN = 201, mod = 998244353;
int f[2][MAXN], g[MAXN][MAXN], t[2][MAXN][MAXN];
// f: expect
inline int read() {
char c = getchar(); int x = 0, f = 1;
while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x * f;
}
int N, a[MAXN], Q, em[MAXN];
int fp(int a, int p) {
int base = 1;
while(p) {
if(p & 1) base = 1ll * base * a % mod;
a = 1ll * a * a % mod; p >>= 1;
}
return base;
}
int inv(int a) {
return fp(a, mod - 2);
}
int add(int x, int y) {
if(x + y < 0) return x + y + mod;
else return x + y >= mod ? x + y - mod : x + y;
}
int mul(int x, int y) {
x = (x + mod) % mod; y = (y + mod) % mod;
return 1ll * x * y % mod;
}
int solve(int id, int o, int N) {//这里dp的时候不能直接表示有j个活着,必须表示除i之外有j个活着。。
memset(g, 0, sizeof(g));
g[0][0] = 1;
for(int i = 1; i <= N; i++) {
for(int j = 0; j <= N; j++) {
if(em[i] ^ id) {
g[i][j] = mul(g[i - 1][j], t[o][em[i]][0]);
if(j) g[i][j] = add(g[i][j], mul(g[i - 1][j - 1], 1 - t[o][em[i]][0]));
}
else g[i][j] = g[i - 1][j];
}
}
int ans = 0;
for(int i = 0; i < N; i++)
ans = add(ans, mul(mul(1 - t[o][id][0], g[N][i]), inv(i + 1)));
return ans;
}
signed main() {
// freopen("a.in", "r", stdin);
// freopen("b.out", "w", stdout);
N = read();
for(int i = 1; i <= N; i++) a[i] = read(), t[0][i][a[i]] = 1, f[0][i] = a[i];
Q = read();
int o = 1;
for(int i = 1; i <= Q; i++, o ^= 1) {
int opt = read();
memcpy(t[o], t[o ^ 1], sizeof(t[o]));
if(opt == 0) {//
int id = read(), u = read(), v = read(), p = 1ll * u * inv(v) % mod;
t[o][id][0] = add(t[o][id][0], mul(p, t[o][id][1]));
for(int j = 1; j <= a[id]; j++) t[o][id][j] = add(mul(p, t[o ^ 1][id][j + 1]), mul(1 - p, t[o ^ 1][id][j]));
} else if(opt == 1) {
int k = read(), cnt = 0;
for(int i = 1; i <= k; i++) em[++cnt] = read();
for(int i = 1; i <= k; i++) printf("%d ", solve(em[i], o, cnt)); puts("");
}
}
for(int i = 1; i <= N; i++) {
int ans = 0;
for(int j = 1; j <= a[i]; j++)
ans = add(ans, mul(j, t[o ^ 1][i][j]));
printf("%d ", ans); }
return 0;
}
/*
*/

100分

#include<bits/stdc++.h>
//#define int long long
using namespace std;
const int MAXN = 201, mod = 998244353;
int f[2][MAXN], g[MAXN][MAXN], t[2][MAXN][MAXN];
// f: expect
inline int read() {
char c = getchar(); int x = 0, f = 1;
while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x * f;
}
int N, a[MAXN], Q, em[MAXN], ans[MAXN], ali[MAXN], tp[MAXN], Inv[MAXN];
int add(int x, int y) {
if(x + y < 0) return x + y + mod;
else return x + y >= mod ? x + y - mod : x + y;
}
int mul(int x, int y) {
x = (x + mod) % mod; y = (y + mod) % mod;
return 1ll * x * y % mod;
}
int fp(int a, int p) {
int base = 1;
while(p) {
if(p & 1) base = 1ll * base * a % mod;
a = 1ll * a * a % mod; p >>= 1;
}
return base;
}
int inv(int a) {
a = add(a, mod);
return fp(a, mod - 2);
} void Pre(int o, int N) {
// memset(g, 0, sizeof(g));
g[0][0] = 1;
for(int i = 1; i <= N; i++) {
ali[i] = (1 - t[o][em[i]][0] + mod) % mod;//alive
for(int j = 0; j <= i; j++) {
g[i][j] = mul(g[i - 1][j], t[o][em[i]][0]);
if(j) g[i][j] = add(g[i][j], mul(g[i - 1][j - 1], ali[i]));
}
}
}
int solve(int id, int o, int N) {
//memset(tp, 0, sizeof(tp));
if(!ali[id]) return 0;
if(ali[id] == 1) {
for(int i = 1; i <= N; i++) tp[i - 1] = g[N][i];
} else {
int down = inv(1 - ali[id]);
tp[0] = mul(g[N][0], down);
for(int i = 1; i <= N; i++)
tp[i] = mul(g[N][i] - mul(tp[i - 1], ali[id]), down);
} int ans = 0;
for(int i = 1; i <= N; i++)
ans = add(ans, mul(mul(ali[id], tp[i - 1]), Inv[i]));
return ans;
}
signed main() {
//freopen("faceless10.in", "r", stdin);
// freopen("b.out", "w", stdout);
N = read();
for(int i = 1; i <= N; i++) a[i] = read(), t[0][i][a[i]] = 1, f[0][i] = a[i], Inv[i] = inv(i);
Q = read();
int o = 1;
for(int i = 1; i <= Q; i++, o ^= 1) {
int opt = read();
memcpy(t[o], t[o ^ 1], sizeof(t[o]));
if(opt == 0) {//
int id = read(), u = read(), v = read(), p = 1ll * u * inv(v) % mod;
t[o][id][0] = add(t[o][id][0], mul(p, t[o][id][1]));
for(int j = 1; j <= a[id]; j++) t[o][id][j] = add(mul(p, t[o ^ 1][id][j + 1]), mul(1 - p, t[o ^ 1][id][j]));
} else if(opt == 1) {
int k = read();
for(int i = 1; i <= k; i++) em[i] = read();
Pre(o, k);
for(int i = k; i >= 1; i--) ans[i] = solve(i, o, k);
for(int i = 1; i <= k; i++) printf("%d ", ans[i]); puts("");
}
}
for(int i = 1; i <= N; i++) {
int ans = 0;
for(int j = 1; j <= a[i]; j++)
ans = add(ans, mul(j, t[o ^ 1][i][j]));
printf("%d ", ans); }
return 0;
}
/*
*/

LOJ#2552. 「CTSC2018」假面(期望 背包)的更多相关文章

  1. loj#2552. 「CTSC2018」假面

    题目链接 loj#2552. 「CTSC2018」假面 题解 本题严谨的证明了我菜的本质 对于砍人的操作好做找龙哥就好了,blood很少,每次暴力维护一下 对于操作1 设\(a_i\)为第i个人存活的 ...

  2. LOJ 2552 「CTSC2018」假面——DP

    题目:https://loj.ac/problem/2552 70 分就是 f[i][j] 表示第 i 个人血量为 j 的概率.这部分是 O( n*Q ) 的:g[i][j][0/1] 表示询问的人中 ...

  3. Loj #2554. 「CTSC2018」青蕈领主

    Loj #2554. 「CTSC2018」青蕈领主 题目描述 "也许,我的生命也已经如同风中残烛了吧."小绿如是说. 小绿同学因为微积分这门课,对"连续"这一概 ...

  4. Loj #2553. 「CTSC2018」暴力写挂

    Loj #2553. 「CTSC2018」暴力写挂 题目描述 temporaryDO 是一个很菜的 OIer .在 4 月,他在省队选拔赛的考场上见到了<林克卡特树>一题,其中 \(k = ...

  5. LOJ 2553 「CTSC2018」暴力写挂——边分治+虚树

    题目:https://loj.ac/problem/2553 第一棵树上的贡献就是链并,转化成 ( dep[ x ] + dep[ y ] + dis( x, y ) ) / 2 ,就可以在第一棵树上 ...

  6. 「CTSC2018」假面

    真~签到题qwq 昨天在考场上先写了个70分暴力dp,然后发现好像可以优化.因为结界技能的模型相当于要求出 对于每个物品,仅仅不选它的背包是什么....  于是当场脑补出两种做法: 前缀和后缀背包卷积 ...

  7. LOJ 2557 「CTSC2018」组合数问题 (46分)

    题目:https://loj.ac/problem/2557 第一个点可以暴搜. 第三个点无依赖关系,k=3,可以 DP .dp[ cr ][ i ][ j ] 表示前 cr 个任务.第一台机器最晚完 ...

  8. LOJ 2555 「CTSC2018」混合果汁——主席树

    题目:https://loj.ac/problem/2555 二分答案,在可以选的果汁中,从价格最小的开始选. 按价格排序,每次可以选的就是一个前缀.对序列建主席树,以价格为角标,维护体积和.体积*价 ...

  9. LOJ 2554 「CTSC2018」青蕈领主——结论(思路)+分治FFT

    题目:https://loj.ac/problem/2554 一个“连续”的区间必然是一个排列.所有 r 不同的.len 最长的“连续”区间只有包含.相离,不会相交,不然整个是一个“连续”区间. 只有 ...

随机推荐

  1. Python数据结构,计算问题

    2018-08-12   <Python 算法>以及<用Python解决数据结构和算法> 什么是算法? 在计算机的世界中,算法本质上是我们对某一个问题或则某一类问题的解决方案. ...

  2. Ajaxa的原生使用方法

    Ajax整合了JavaScript.xml.CSS等现有技术而成,全称为Asynchronous JavaScript And XML,即异步的 JavaScript和xml.它使用了JavaScri ...

  3. SpringMVC的简单介绍及使用

    一.简介 1.SpringMVC和Spring的关系: >软件开发的三层架构: web层[表示层.表现层]---->Service层---->Dao[DataBase Access ...

  4. Flink学习笔记:Connectors概述

    本文为<Flink大数据项目实战>学习笔记,想通过视频系统学习Flink这个最火爆的大数据计算框架的同学,推荐学习课程: Flink大数据项目实战:http://t.cn/EJtKhaz ...

  5. Idea中文输入问题2

    Desc: win10 idea2017版本+jdk1.9 输入中文无法光标跟随 解决过程: 网上的各种三大类型教程(1)删除jre64(2)删除jre64,然后复制jdk的jre到idea目录,最后 ...

  6. [jvm]垃圾回收与内存分配策略

    一.垃圾回收算法 概述 JVM中,当创建的对象不再被使用的时候,此时我们认为他是无用的“垃圾”:在现代主流的商用jvm中,都是通过可达性分析来判断对象是否存活的.这个算法的基本思想是通过一系列“GCR ...

  7. linux负载均衡与性能监控

    平均负载是单位时间内, 系统处于可运行状态和不可中断状态的平均进程数( 平均活跃进程数 ) 可运行状体好理解, 就是进程正在运行状态Running和可运行状态Runnable... 这里需要注意的是 ...

  8. Ubuntu Server 中实际内存与物理内存不相等的问题

    记录 来源 v2ex,提到了一个平时不是很起眼的问题,Ubuntu Server 中系统默认会占用 128M 内存,用于 CVM 内部的 kdump 服务. 科普 查看 CVM 所拥有的物理内存 通过 ...

  9. I Hate It(线段树区间最值,单点更新)-------------蓝桥备战系列

    很多学校流行一种比较的习惯.老师们很喜欢询问,从某某到某某当中,分数最高的是多少.  这让很多学生很反感.  不管你喜不喜欢,现在需要你做的是,就是按照老师的要求,写一个程序,模拟老师的询问.当然,老 ...

  10. HDU 6189 Law of Commutation(规律)

    题意: 给定n,a,求区间 [ 1 , 1<<n ] 的数b 满足 的个数 分析:打出暴力程序可以发现当a为奇数的时候结果为一: 当a为偶时 , a^b=2^(k+b)mod 2^n ; ...