原文链接www.cnblogs.com/zhouzhendong/p/UOJ469.html

前言

clytql当场秒掉此题可惜不知道为什么fst了。

题解

考虑构建指数生成函数。

对于第 \(i\) 项,设其概率为 \(p_i\) (即题目中的 \(p_i / \sum_i p_i\)) 。构建指数生成函数:

\[f_i(x) = \sum_{j\geq 0, j\bmod 2 = s_i} p_i ^ j \frac {x^ j } { j !} \\ = \frac 1 2 (e ^ {p_i x } + (-1)^{s_i} e ^ {-p_i x })
\]

\(F(x) = \prod_i f_i(x) ,f(x) = \sum_{i} i! [x^i]F(x)\) 的 \(k\) 次项系数就是随机按 \(k\) 次开关到达指定状态的概率。

我们要求的是第一次到达指定状态的概率,所以我们需要将多项式 \(f(x)\) 除去"\(s_i\) 全为 0 时的多项式 \(g(x)\)"。

我们要算的是期望,所以我们要求的是

\[\frac{\rm d} { {\rm d} x } \left ( \frac {f(x)}{g(x)}\right )
\]

的各个系数之和。注意由于我们在求 \(f(x)\)、\(g(x)\) 时,就已经乘了一个阶乘将指数生成函数转化成对应的普通生成函数了。因为我们要除去的方案是从终止状态出发再回到终止状态的方案数(OGF),而不是在到达终止状态之前绕一圈的方案数(如果除以EGF)。

由于

\[\cfrac{\rm d} { {\rm d} x } \left ( \cfrac {f(x)}{g(x)} \right ) = \cfrac{f'(x) g(x) - g'(x) f(x) }{g ^ 2(x)}
\]

于是,我们来对每一个项考虑一下:

\[e ^ {kx} = \sum_{i\geq 0 } k ^ i \frac { x ^ i } { i ! }
\]

\[\sum_{i\geq 0} k ^ i x ^ i= \frac{1}{1 - kx}
\]

\[\frac{\rm d} { {\rm d} x } e ^ {kx} = k ^ 2 x e ^ {kx} = k ^ 2 x \sum_{i\geq 0 } k ^ i \frac { x ^ i } { i ! }
\]

\[\sum_{i\geq 1} k ^ {i+1} i \cdot x ^ i = \frac {k} { (1-kx) ^ 2}
\]

接下来我们把 \(x = 1\) 代入求解。

考虑到当 \(k = 1\) 时我们会得到 NAN,这导致了求解失败。

但是我们显然可以肯定答案不是 NAN。那么发生了什么?

之前提到,答案是

\[\cfrac{f'(x) g(x) - g'(x) f(x) }{g ^ 2(x)}
\]

我们只需要将分子分母上下同乘 \((1-kx) ^ 2\) 。

注意到 \(g^2(x)\) 里面有 \(\cfrac {1}{(1-kx) ^ 2}\) ,但是 $f'(x) g(x) $ 和 \(f(x)g'(x)\) 里面都有 \(\cfrac {1}{(1-kx) ^ 3}\) ,看起来似乎又是 NAN。注意到 $f'(x) g(x) $ 和 \(f(x)g'(x)\) 里面的 \(\cfrac {1}{(1-kx) ^ 3}\) 项在减法时抵消了,所以没有影响。

总时间复杂度 \(O(n \sum{p_ i} )\) 。

代码

  1. #include <bits/stdc++.h>
  2. #define clr(x) memset(x,0,sizeof x)
  3. #define For(i,a,b) for (int i=(a);i<=(b);i++)
  4. #define Fod(i,b,a) for (int i=(b);i>=(a);i--)
  5. #define fi first
  6. #define se second
  7. #define pb(x) push_back(x)
  8. #define mp(x,y) make_pair(x,y)
  9. #define outval(x) cerr<<#x" = "<<x<<endl
  10. #define outtag(x) cerr<<"---------------"#x"---------------"<<endl
  11. #define outarr(a,L,R) cerr<<#a"["<<L<<".."<<R<<"] = ";\
  12. For(_x,L,R)cerr<<a[_x]<<" ";cerr<<endl;
  13. using namespace std;
  14. typedef long long LL;
  15. typedef unsigned long long ULL;
  16. typedef vector <int> vi;
  17. LL read(){
  18. LL x=0,f=0;
  19. char ch=getchar();
  20. while (!isdigit(ch))
  21. f|=ch=='-',ch=getchar();
  22. while (isdigit(ch))
  23. x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
  24. return f?-x:x;
  25. }
  26. const int N=105,S=1e5+10,mod=998244353;
  27. int Pow(int x,int y){
  28. int ans=1;
  29. for (;y;y>>=1,x=(LL)x*x%mod)
  30. if (y&1)
  31. ans=(LL)ans*x%mod;
  32. return ans;
  33. }
  34. void Add(int &x,int y){
  35. if ((x+=y)>=mod)
  36. x-=mod;
  37. }
  38. void Del(int &x,int y){
  39. if ((x-=y)<0)
  40. x+=mod;
  41. }
  42. int Add(int x){
  43. return x>=mod?x-mod:x;
  44. }
  45. int Del(int x){
  46. return x<0?x+mod:x;
  47. }
  48. int inv2=(mod+1)>>1;
  49. int n;
  50. int s[N],p[N],sum=0,invs;
  51. int f[S],g[S],val[S],inv[N],O=5e4+5;
  52. int ans=0;
  53. void Get(int *a){
  54. static int b[S];
  55. For(i,-sum,sum){
  56. a[i+O]=0;
  57. val[i+O]=(LL)Del(i)*invs%mod;
  58. inv[i+O]=Pow(Del(1-val[i+O]),mod-2);
  59. }
  60. a[0+O]=1;
  61. For(i,1,n){
  62. For(j,-sum,sum)
  63. b[j+O]=0;
  64. For(j,-sum,sum){
  65. if (!a[j+O])
  66. continue;
  67. Add(b[j+p[i]+O],a[j+O]);
  68. if (s[i])
  69. Del(b[j-p[i]+O],a[j+O]);
  70. else
  71. Add(b[j-p[i]+O],a[j+O]);
  72. }
  73. For(j,-sum,sum)
  74. a[j+O]=b[j+O];
  75. }
  76. }
  77. int calc1(int *a,int *b){
  78. // a' * b * (1 - x) ^ 2
  79. int ans=0;
  80. For(i,-sum,sum-1)
  81. Add(ans,(LL)b[i+O]*inv[i+O]%mod);
  82. ans=(LL)ans*a[sum+O]%mod;
  83. return ans;
  84. }
  85. int calc2(int *a){
  86. return (LL)a[sum+O]*a[sum+O]%mod;
  87. }
  88. int main(){
  89. n=read();
  90. For(i,1,n)
  91. s[i]=read();
  92. For(i,1,n)
  93. p[i]=read(),sum+=p[i];
  94. invs=Pow(sum,mod-2);
  95. Get(f),clr(s),Get(g);
  96. Add(ans,calc1(f,g));
  97. Del(ans,calc1(g,f));
  98. ans=(LL)ans*Pow(calc2(g),mod-2)%mod;
  99. cout<<ans<<endl;
  100. return 0;
  101. }

UOJ#469. 【ZJOI2019】开关 生成函数的更多相关文章

  1. [ZJOI2019] 开关 (一种扩展性较高的做法)

    [ZJOI2019] 开关 (一种扩展性较高的做法) 题意: 有n个开关,一开始状态都为关闭.每次随机选出一个开关将其状态改变,选出第i个开关的概率为${ p_i \over \sum_{i=1}^n ...

  2. [ZJOI2019]开关(生成函数+背包DP)

    注:以下p[i]均表示概率 设F(x)为按i次开关后到达终止状态方案数的EGF,显然F(x)=π(ep[i]x/p+(-1)s[i]e-p[i]x/p)/2,然而方案包含一些多次到达合法方案的状态,需 ...

  3. [ZJOI2019]开关

    以下的方案数默认是带权方案数.设\(P=\sum_{i=1}^np_i\). 设\(F(x)\)为按\(i\)次开关后到达终止态的方案数的EGF,\(f\)为\(F\)的OGF,显然\(F(x)=\p ...

  4. 【UOJ#450】【集训队作业2018】复读机(生成函数,单位根反演)

    [UOJ#450][集训队作业2018]复读机(生成函数,单位根反演) 题面 UOJ 题解 似乎是\(\mbox{Anson}\)爷的题. \(d=1\)的时候,随便怎么都行,答案就是\(k^n\). ...

  5. Loj #3045. 「ZJOI2019」开关

    Loj #3045. 「ZJOI2019」开关 题目描述 九条可怜是一个贪玩的女孩子. 这天,她和她的好朋友法海哥哥去玩密室逃脱.在他们面前的是 \(n\) 个开关,开始每个开关都是关闭的状态.要通过 ...

  6. LOJ 3045: 洛谷 P5326: 「ZJOI2019」开关

    题目传送门:LOJ #3045. 题意简述 略. 题解 从高斯消元出发好像需要一些集合幂级数的知识,就不从这个角度思考了. 令 \(\displaystyle \dot p = \sum_{i = 1 ...

  7. UOJ#450. 【集训队作业2018】复读机 排列组合 生成函数 单位根反演

    原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ450.html 题解 首先有一个东西叫做“单位根反演”,它在 FFT 的时候用到过: $$\frac 1 ...

  8. uoj#335. 【清华集训2017】生成树计数(prufer序列+生成函数+多项式)

    传送门 好神仙的题目--又一次有了做一题学一堆的美好体验 据说本题有第二类斯特林数+分治\(FFT\)的做法,然而咱实在看不懂写的是啥,题解贴这里,有兴趣的可以自己去瞅瞅,看懂了记得回来跟咱讲讲 前置 ...

  9. 【loj3045】【ZJOI2019】开关

    题目 \(n\)个开关,一开始处于关闭状态,你需要将他们按成\(s\)状态,按成了之后就停止操作; 每次按下开关的i概率为\(\frac{p_i}{\sum_{i=1}^{n}p_i}\) ,问期望步 ...

随机推荐

  1. String字符串创建方法

    String字符串的创建方法我们总结为3+1,3是一共有3种构造方法,1是有一种特殊的创建方法. 首先来看3种构造方法: 1.new String()  无参构造 用该方法创建的字符串是一个空字符串, ...

  2. SQL注入绕过技巧

    1.绕过空格(注释符/* */,%a0): 两个空格代替一个空格,用Tab代替空格,%a0=空格: % % %0a %0b %0c %0d %a0 %00 /**/ /*!*/ 最基本的绕过方法,用注 ...

  3. 转换属性transform

    transform: rotate(45deg);旋转 rotate(值) 值为正,表示元素顺时针旋转 值为负,表示元素逆时针旋转 transform: translate(200px,100px); ...

  4. Vivado中备份设计好的block design

    参考链接 https://blog.csdn.net/dimples_song/article/details/81391615 前言 为了不每次都重新生成block design,避免重复劳动. 可 ...

  5. Android JSBridge原理与实现

    在Android中,JSBridge已经不是什么新鲜的事物了,各家的实现方式也略有差异.大多数人都知道WebView存在一个漏洞,详细信息见你不知道的 Android WebView 使用漏洞,虽然该 ...

  6. Python多版本环境搭建(Linux系统)

    python Linux 环境 (版本隔离工具)   首先新建用户,养成良好习惯   useradd python   1.安装pyenv   GitHub官网:   https://github.c ...

  7. 用js刷剑指offer(把数组排成最小的数)

    题目描述 输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个.例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323. 思路 对ve ...

  8. linux系统编程之信号(六)

    今天继续学习信号相关的知识,主要还是学习sigqueue另外信号发送函数,并配合上节学习的sigaction的用法,进入正题: sigqueue函数: sigval联合体: 实际上sigval参数是用 ...

  9. Maven02 -学习总结&学习文档 -踩坑123

    maven在开发中的作用 ①自动添加第三方 jar 包 在今天的 JavaEE 开发领域,有大量的第三方框架和工具可以供我们使用.要使用这些 jar 包最简单的方法就是复制粘贴到 WEB-INF/li ...

  10. python算法与数据结构-选择排序算法(33)

    一.选择排序的介绍 选择排序(Selection sort)是一种简单直观的排序算法.首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素, ...