#565. 「LibreOJ Round #10」mathematican 的二进制(期望 + 分治NTT)
题面
题解
首先我们发现,操作是可以不考虑顺序的,因为每次操作会加一个 \(1\) ,每次进位会减少一个 \(1\) ,我们就可以考虑最后 \(1\) 的个数(也就是最后的和),以及成功操作次数,就行了。
然后根据期望的线性性,我们可以从低到高按位考虑贡献。
考虑一个递推:\(f(i, j)\) 表示从后往前第 \(i\) 位总共被改变 \(j\) 次的概率,那么有两种转移:
- 进位:\(\displaystyle f(i - 1, j) \to f(i, \lfloor \frac j 2 \rfloor)\)
- 操作:对于第 \(i\) 位每个概率为 \(p\) 的操作, \(f(i, j - 1)p + f(i, j)(1 - p) \to f(i, j)\)
注意要先转移第一个,再转移第二个,因为第二个可以对于第一个操作上来的数位进行贡献。
然后这样直接实现就是 \(O(m^2)\) 的,但是我们可以考虑优化,对于第二个容易观察就是乘上了 \(P(x) = \prod_i p_ix + (1-p_i)\) 这个生成函数。
显然这个我们可以利用 **分治 \(NTT\) ** 来解决。
进位的话我们可以暴力进位,因为每个操作对于 **分治 \(NTT\) ** 的贡献可以放缩成一个等比级数:\(\displaystyle \sum_{i = 0} ^ {\infty} 2^{-i} = 2\) 。
所以最后时间复杂度就是 \(O(m \log^2 m)\) 的。
总结
对于一些期望题,可以考虑期望的线性性,以及试试操作顺序是否不影响答案。
然后考虑 \(NTT\) 优化概率生成函数就行啦。
代码
#include <bits/stdc++.h>
#define For(i, l, r) for(register int i = (l), i##end = (int)(r); i <= i##end; ++i)
#define Fordown(i, r, l) for(register int i = (r), i##end = (int)(l); i >= i##end; --i)
#define Set(a, v) memset(a, v, sizeof(a))
#define Cpy(a, b) memcpy(a, b, sizeof(a))
#define debug(x) cout << #x << ": " << (x) << endl
#define DEBUG(...) fprintf(stderr, __VA_ARGS__)
#define pb push_back
using namespace std;
typedef long long ll;
template<typename T> inline bool chkmin(T &a, T b) {return b < a ? a = b, 1 : 0;}
template<typename T> inline bool chkmax(T &a, T b) {return b > a ? a = b, 1 : 0;}
inline int read() {
int x(0), sgn(1); char ch(getchar());
for (; !isdigit(ch); ch = getchar()) if (ch == '-') sgn = -1;
for (; isdigit(ch); ch = getchar()) x = (x * 10) + (ch ^ 48);
return x * sgn;
}
void File() {
#ifdef zjp_shadow
freopen ("565.in", "r", stdin);
freopen ("565.out", "w", stdout);
#endif
}
const int N = 200100, Mod = 998244353;
ll fpm(ll x, int power) {
ll res = 1;
for (; power; power >>= 1, (x *= x) %= Mod)
if (power & 1) (res *= x) %= Mod;
return res;
}
inline int Add(int a, int b) { return (a += b) >= Mod ? a - Mod : a; }
template<int Maxn>
struct Number_Theoretic_Transfrom {
const int g = 3;
ll powg[Maxn + 5], invpowg[Maxn + 5]; int rev[Maxn + 5];
void NTT_Init() {
for (int i = 2; i <= Maxn; i <<= 1)
invpowg[i] = fpm((powg[i] = fpm(g, (Mod - 1) / i)), Mod - 2);
}
int len;
void NTT(ll P[], int opt) {
For (i, 0, len - 1)
if (i < rev[i]) swap(P[i], P[rev[i]]);
for (int i = 2, p = 1; i <= len; p = i, i <<= 1) {
ll Wi = opt == 1 ? powg[i] : invpowg[i];
for (int j = 0; j < len; j += i) {
ll x = 1;
For (k, 0, p - 1) {
ll u = P[j + k], v = P[j + k + p] * x % Mod;
P[j + k] = Add(u, v);
P[j + k + p] = Add(u, Mod - v);
(x *= Wi) %= Mod;
}
}
}
if (!~opt) {
ll invn = fpm(len, Mod - 2);
For (i, 0, len - 1) (P[i] *= invn) %= Mod;
}
}
ll A[Maxn + 5], B[Maxn + 5];
void Mult(int *a, int *b, int *c, int lena, int lenb) {
int cnt = 0;
for (len = 1; len <= lena + lenb; len <<= 1) ++ cnt;
For (i, 0, len - 1)
rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (cnt - 1));
For (i, 0, len - 1)
A[i] = i <= lena ? a[i] : 0, B[i] = i <= lenb ? b[i] : 0;
NTT(A, 1); NTT(B, 1); For (i, 0, len - 1) (A[i] *= B[i]) %= Mod; NTT(A, -1);
For (i, 0, lena + lenb) c[i] = A[i];
}
};
Number_Theoretic_Transfrom<1 << 20> NTT;
int n, m;
int pool[N << 5], *ptr = pool;
struct Poly {
int *a, len;
Poly(int l) { a = ptr; ptr += (len = l) + 1; }
void Out() {
debug(len);
For (i, 1, n) printf ("%d%c", a[i], i == iend ? '\n' : ' ');
}
};
inline bool operator < (const Poly &lhs, const Poly &rhs) {
return lhs.len > rhs.len;
}
vector<int> Base[N];
Poly I(0);
Poly Calc(int id) {
if (!(bool)Base[id].size()) return I;
priority_queue<Poly> P;
for (int prob : Base[id]) {
Poly cur(1);
cur.a[1] = prob;
cur.a[0] = Mod + 1 - prob;
P.push(cur);
}
while (P.size() > 1) {
Poly a = P.top(); P.pop();
Poly b = P.top(); P.pop();
Poly c(a.len + b.len);
NTT.Mult(a.a, b.a, c.a, a.len, b.len);
P.push(c);
}
return P.top();
}
int main () {
File();
NTT.NTT_Init();
n = read(); m = read();
For (i, 1, m) {
int pos = read(), x = read(), y = read();
Base[pos].pb(1ll * x * fpm(y, Mod - 2) % Mod);
}
ll ans = 0;
Poly res(0); res.a[0] = 1;
For (i, 0, n + 20) {
Poly tmp = Calc(i);
if (tmp.len) {
NTT.Mult(res.a, tmp.a, res.a, res.len, tmp.len);
res.len = res.len + tmp.len;
}
For (j, 0, res.len) {
ans = (ans + 1ll * res.a[j] * j) % Mod;
int temp = res.a[j]; res.a[j] = 0;
(res.a[j >> 1] += temp) %= Mod;
}
res.len >>= 1;
}
printf ("%lld\n", ans);
return 0;
}
#565. 「LibreOJ Round #10」mathematican 的二进制(期望 + 分治NTT)的更多相关文章
- LOJ#565. 「LibreOJ Round #10」mathematican 的二进制 分治,FFT,概率期望
原文链接www.cnblogs.com/zhouzhendong/p/LOJ565.html 前言 标算真是优美可惜这题直接暴力FFT算一算就solved了. 题解 首先,假装没有进位,考虑解决这个问 ...
- LOJ565. 「LibreOJ Round #10」mathematican 的二进制(NTT)
题目链接 https://loj.ac/problem/565 题解 首先,若进行所有操作之后成功执行的操作数为 \(m\),最终得到的数为 \(w\),那么发生改变的二进制位的数量之和(即代价之和) ...
- 【LOJ565】【LibreOJ Round #10】mathematican 的二进制 DP 分治FFT
题目大意 有一个无限长的二进制串,初始时它的每一位都为 \(0\).现在有 \(m\) 个操作,其中第 \(i\) 个操作是将这个二进制串的数值加上 \(2^{a_i}\).我们称每次操作的代价是这次 ...
- [LOJ#531]「LibreOJ β Round #5」游戏
[LOJ#531]「LibreOJ β Round #5」游戏 试题描述 LCR 三分钟就解决了问题,她自信地输入了结果-- > -- 正在检查程序 -- > -- 检查通过,正在评估智商 ...
- [LOJ#530]「LibreOJ β Round #5」最小倍数
[LOJ#530]「LibreOJ β Round #5」最小倍数 试题描述 第二天,LCR 终于启动了备份存储器,准备上传数据时,却没有找到熟悉的文件资源,取而代之的是而屏幕上显示的一段话: 您的文 ...
- [LOJ#516]「LibreOJ β Round #2」DP 一般看规律
[LOJ#516]「LibreOJ β Round #2」DP 一般看规律 试题描述 给定一个长度为 \(n\) 的序列 \(a\),一共有 \(m\) 个操作. 每次操作的内容为:给定 \(x,y\ ...
- [LOJ#515]「LibreOJ β Round #2」贪心只能过样例
[LOJ#515]「LibreOJ β Round #2」贪心只能过样例 试题描述 一共有 \(n\) 个数,第 \(i\) 个数 \(x_i\) 可以取 \([a_i , b_i]\) 中任意值. ...
- [LOJ#525]「LibreOJ β Round #4」多项式
[LOJ#525]「LibreOJ β Round #4」多项式 试题描述 给定一个正整数 k,你需要寻找一个系数均为 0 到 k−1 之间的非零多项式 f(x),满足对于任意整数 x 均有 f(x) ...
- [LOJ#526]「LibreOJ β Round #4」子集
[LOJ#526]「LibreOJ β Round #4」子集 试题描述 qmqmqm有一个长为 n 的数列 a1,a2,……,an,你需要选择集合{1,2,……,n}的一个子集,使得这个子集中任意两 ...
随机推荐
- 学习memcache
本文参考了菜鸟教程中的内容. 安装 安装memcache的时候,请切换为root用户 root@centos # wget http://www.memcached.org/files/memcach ...
- 通过arcmap发布缓存服务,无法选择自定义方案
出现该问题是因为缓存目录有该缓存信息,清楚掉之后就可以选择自定义方案了
- Java 中的String、StringBuilder与StringBuffer的区别联系(转载)
1 String 基础 想要了解一个类,最好的办法就是看这个类的源代码,String类源代码如下: public final class String implements java.io.Seria ...
- Auzre系列1.1.1 —— 安装用于 IntelliJ 的 Azure 工具包
(文中大部分内容(95%)Azure官网上有,我只是把我自己实际操作中遇到的问题在这里阐述一下.) 先决条件 若要完成文章中的步骤,需要安装用于 IntelliJ 的 Azure 工具包,该工具包需要 ...
- jackson使用问题:mapper.readValue()将JSON字符串转反序列化为对象失败或异常
问题根源:转化目标实体类的属性要与被转JSON字符串总的字段 一 一对应!字符串里可以少字段,但绝对不能多字段. 先附上我这段出现了问题的源码: // 1.接收并转化相应的参数.需要在pom.xml中 ...
- 老男孩python学习自修第十六天【常用模块之sys和os】
例子: sys.argv 命令行参数List,第一个元素是程序本身路径 sys.exit(n) 退出程序,正常退出时exit(0) sys.version 获取Python解释程序的版本信息 sys. ...
- 使用PHP进行SOCKET编程
一.SOCKET原理图 二.SOCKET常用函数 1.创建socket函数: resource socket_create ( int $domain , int $type , int $proto ...
- Yii2的使用
yii2的下载安装 使用下载好的文件配置高级模板,在配置文件配置好数据库和gii 在common模板配置db: 在backend模板配置gii: 配置nginx服务器访问backend和fronten ...
- Jackson将对象转换为json字符串时,设置默认的时间格式
maven需要的依赖: <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifac ...
- HTTP协议 - 使用php模拟get/post请求
首先 有个疑问, 是不是只有浏览器才能发送http 请求? 答案肯定是错的,第一篇就说了,http是由请求行,请求头,请求主体三个部分组成,那么我们可不可以用代码来模拟一下get和post请求呢: 首 ...