DP式子比后面的东西难推多了

LOJ2304

Luogu P3824

UOJ #316


题意

给定一个长度为$ n$高为$ \infty$的矩形

每个点有$ 1-P$的概率不可被选择

求最大的和底边重合的不包含不可选点的矩形的面积为$ K$的概率

$ n \leq 10^9 k \leq 10^3$


题解

K可以出到50000的

首先考虑DP

面积恰好为$ K$的概率可以差分为不高于$ K$的概率减去不高于$ K-1$的概率

设$ f[i][j]$表示长度为$ i$的矩形,从底边起$ j$行都可选,最大面积不大于$ K$的概率

边界为$ f[0][j]=1,f[i][j]=0 当且仅当i*j>k$

考虑转移,要么第$ j+1$行也都可选,要么第$ j+1$行有不可选的位置

对于第二种情况我们枚举从左到右第一个不可选的位置

有转移方程式

$$f[i][j]=f[i][j+1]*P^i+\sum_{k=1}^iP^{k-1}(1-P)f[k-1][j+1]·f[i-k][j]$$

我们要求的是$ f[n][0]$

由于$ i*j \leq K$因此复杂度大致是$ n·k \log k$的

可以得$ 70$分

容易发现当$ n$远大于$ k$的时候,每连续$ k$列必然有一列最低端有不可选点

令$ F[i]$表示当$ i>k$时,长度为$ i$的矩形的答案

枚举从右往左第一个不可选点,有转移方程式

$$ F[i]=f[i-k]*(1-P)*f[k-1][1]*P^{k-1}$$

这是一个线性递推的标准形式,可以用特征多项式优化到$ O(k^2 \log n)$甚至$ O(k \log k \log n)$

如果采用后一种的话复杂度的瓶颈在于前面的$ O(k^2)DP$,这部分可以用分治$ NTT$优化

然而我并没有写


代码

  1. #include<ctime>
  2. #include<cmath>
  3. #include<cstdio>
  4. #include<cstring>
  5. #include<iostream>
  6. #include<algorithm>
  7. #include<queue>
  8. #include<vector>
  9. #define p 998244353
  10. #define rt register int
  11. #define ll long long
  12. using namespace std;
  13. inline ll read(){
  14. ll x=;char zf=;char ch=getchar();
  15. while(ch!='-'&&!isdigit(ch))ch=getchar();
  16. if(ch=='-')zf=-,ch=getchar();
  17. while(isdigit(ch))x=x*+ch-'',ch=getchar();return x*zf;
  18. }
  19. void write(ll y){if(y<)putchar('-'),y=-y;if(y>)write(y/);putchar(y%+);}
  20. void writeln(const ll y){write(y);putchar('\n');}
  21. namespace poly{
  22. vector<int>R;
  23. int ksm(int x,int y=p-){
  24. int ans=;
  25. for(rt i=y;i;i>>=,x=1ll*x*x%p)if(i&)ans=1ll*ans*x%p;
  26. return ans;
  27. }
  28. void NTT(int n,vector<int>&A,int fla){
  29. A.resize(n);
  30. for(rt i=;i<n;i++)if(i>R[i])swap(A[i],A[R[i]]);
  31. for(rt i=;i<n;i<<=){
  32. int w=ksm(,(p-)//i);
  33. for(rt j=;j<n;j+=i<<){
  34. int K=;
  35. for(rt k=;k<i;k++,K=1ll*K*w%p){
  36. int x=A[j+k],y=1ll*K*A[i+j+k]%p;
  37. A[j+k]=(x+y)%p,A[i+j+k]=(x-y)%p;
  38. }
  39. }
  40. }
  41. if(fla==-){
  42. reverse(A.begin()+,A.end());
  43. int invn=ksm(n);
  44. for(rt i=;i<n;i++)A[i]=1ll*A[i]*invn%p;
  45. }
  46. }
  47. vector<int>Mul(vector<int>x,vector<int>y){
  48. int lim=,sz=x.size()+y.size()-;
  49. while(lim<=sz)lim<<=;R.resize(lim);
  50. for(rt i=;i<lim;i++)R[i]=(R[i>>]>>)|(i&)*(lim>>);
  51. NTT(lim,x,);NTT(lim,y,);
  52. for(rt i=;i<lim;i++)x[i]=1ll*x[i]*y[i]%p;
  53. NTT(lim,x,-);x.resize(sz);
  54. return x;
  55. }
  56. vector<int>sqr(vector<int>x){
  57. int lim=,sz=x.size()*-;
  58. while(lim<=sz)lim<<=;R.resize(lim);
  59. for(rt i=;i<lim;i++)R[i]=(R[i>>]>>)|(i&)*(lim>>);
  60. NTT(lim,x,);for(rt i=;i<lim;i++)x[i]=1ll*x[i]*x[i]%p;
  61. NTT(lim,x,-);x.resize(sz);
  62. return x;
  63. }
  64. vector<int>Inv(vector<int>A,int n=-){
  65. if(n==-)n=A.size();
  66. if(n==)return vector<int>(,ksm(A[]));
  67. vector<int>b=Inv(A,(n+)/);
  68. int lim=;while(lim<=n+n)lim<<=;R.resize(lim);
  69. for(rt i=;i<lim;i++)R[i]=(R[i>>]>>)|(i&)*(lim>>);
  70. A.resize(n);NTT(lim,A,);NTT(lim,b,);
  71. for(rt i=;i<lim;i++)A[i]=1ll*b[i]*(2ll-1ll*A[i]*b[i]%p)%p;
  72. NTT(lim,A,-);A.resize(n);
  73. return A;
  74. }
  75. vector<int>Div(vector<int>A,vector<int>B){
  76. int n=A.size(),m=B.size();
  77. reverse(A.begin(),A.end());
  78. reverse(B.begin(),B.end());
  79. A.resize(n-m+),B.resize(n-m+);
  80. int lim=;while(lim<=*(n-m+))lim<<=;R.resize(lim);
  81. for(rt i=;i<lim;i++)R[i]=(R[i>>]>>)|(i&)*(lim>>);
  82. vector<int>ans=Mul(A,Inv(B));ans.resize(n-m+);
  83. reverse(ans.begin(),ans.end());
  84. return ans;
  85. }
  86. vector<int>add(vector<int>A,vector<int>B){
  87. int len=max(A.size(),B.size());A.resize(len+);
  88. for(rt i=;i<=len;i++)(A[i]+=B[i])%=p;
  89. return A;
  90. }
  91. vector<int>sub(vector<int>A,vector<int>B){
  92. int len=max(A.size(),B.size());A.resize(len+);
  93. for(rt i=;i<=len;i++)(A[i]-=B[i])%=p;
  94. return A;
  95. }
  96. vector<int>Mod(vector<int>x,vector<int>y){
  97. if(x.size()<=y.size())return x;
  98. vector<int>ans=Div(x,y);
  99. ans=sub(x,Mul(y,ans));
  100. while(!ans[ans.size()-])ans.pop_back();
  101. if(ans.size()>y.size())ans.resize(y.size());
  102. return ans;
  103. }
  104. }
  105. using namespace poly;
  106. int a[];
  107. vector<int>fmo;
  108. vector<int>ksm(vector<int>x,int y){
  109. if(y==)return x;
  110. vector<int>ans=Mod(sqr(ksm(x,y>>)),fmo);
  111. if(y&){
  112. ans.push_back();
  113. for(rt i=ans.size()-;i>=;i--)ans[i+]=ans[i],ans[i]=;
  114. }
  115. return ans;
  116. }
  117. using namespace poly;
  118. int k,m,n,x,y,z,cnt,ans,K,P;
  119. int f[][],mi[];
  120. //f[i][j]长度为i合法高度最低至少为j的合法概率
  121. void calc(int n,int K,int fla){
  122. memset(f,,sizeof(f));
  123. for(rt i=;i<=K+;i++)f[][i]=;
  124. for(rt i=;i<=K+;i++)
  125. for(rt j=K/i;j>=;j--){
  126. f[i][j]=1ll*f[i][j+]*mi[i]%p;
  127. for(rt k=;k<=i;k++)(f[i][j]+=1ll*f[k-][j+]*mi[k-]%p*(+p-P)%p*f[i-k][j]%p)%=p;
  128. }
  129. fmo.resize(K+);
  130. for(rt j=;j<=K+;j++)fmo[K+-j]=-1ll*mi[j-]*f[j-][]%p*(p+-P)%p;
  131. fmo[K+]=;int ret=;
  132. if(n<=K+)ret=f[n][];else {
  133. vector<int>x;x.push_back();x.push_back();
  134. x=ksm(x,n);
  135. for(rt i=;i<=K+;i++)(ret+=1ll*f[i][]*x[i]%p)%=p;
  136. }
  137. (ans+=ret*fla)%=p;
  138. }
  139. int main(){
  140. // file("pool");
  141. n=read();K=read();x=read();y=read();P=1ll*x*ksm(y)%p;
  142. mi[]=;for(rt i=;i<=K+;i++)mi[i]=1ll*mi[i-]*P%p;
  143. calc(n,K,);calc(n,K-,-);cout<<(ans+p)%p;
  144. return ;
  145. }

「NOI2017」泳池的更多相关文章

  1. LOJ#2304. 「NOI2017」泳池

    $n \leq 1e9$底边长的泳池,好懒啊泥萌自己看题吧,$k \leq 1000$.答案对998244353取膜. 现在令$P$为安全,$Q$为危险的概率.刚好$K$是极其不好算的,于是来算$\l ...

  2. LOJ 2304 「NOI2017」泳池——思路+DP+常系数线性齐次递推

    题目:https://loj.ac/problem/2304 看了各种题解…… \( dp[i][j] \) 表示有 i 列.第 j 行及以下默认合法,第 j+1 行至少有一个非法格子的概率,满足最大 ...

  3. LOJ_2305_「NOI2017」游戏 _2-sat

    LOJ_2305_「NOI2017」游戏 _2-sat 题意: 给你一个长度为n的字符串S,其中第i个字符为a表示第i个地图只能用B,C两种赛车,为b表示第i个地图只能用A,C两种赛车,为c表示第i个 ...

  4. 「NOI2017」游戏

    「NOI2017」游戏 题目描述 小 L 计划进行 \(n\) 场游戏,每场游戏使用一张地图,小 L 会选择一辆车在该地图上完成游戏. 小 L 的赛车有三辆,分别用大写字母 \(A\).\(B\).\ ...

  5. loj #2305. 「NOI2017」游戏

    #2305. 「NOI2017」游戏 题目描述 小 L 计划进行 nnn 场游戏,每场游戏使用一张地图,小 L 会选择一辆车在该地图上完成游戏. 小 L 的赛车有三辆,分别用大写字母 AAA.BBB. ...

  6. LOJ2305 「NOI2017」游戏

    「NOI2017」游戏 题目背景 狂野飙车是小 L 最喜欢的游戏.与其他业余玩家不同的是,小 L 在玩游戏之余,还精于研究游戏的设计,因此他有着与众不同的游戏策略. 题目描述 小 L 计划进行$n$场 ...

  7. LOJ2303 「NOI2017」蚯蚓排队

    「NOI2017」蚯蚓排队 题目描述 蚯蚓幼儿园有$n$只蚯蚓.幼儿园园长神刀手为了管理方便,时常让这些蚯蚓们列队表演. 所有蚯蚓用从$1$到$n$的连续正整数编号.每只蚯蚓的长度可以用一个正整数表示 ...

  8. LibreOJ2302 - 「NOI2017」整数

    Portal Description 有一个整数\(x=0\),对其进行\(n(n\leq10^6)\)次操作: 给出\(a(|a|\leq10^9),b(b\leq30n)\),将\(x\)加上\( ...

  9. 「NOI2017」蔬菜 解题报告

    「NOI2017」蔬菜 首先考虑流 可以从 \(s\) 流入表示得到蔬菜,流出到 \(t\) 表示卖出蔬菜,给每个蔬菜拆点,并给它它每天应得的蔬菜. 但是我们没办法直接给,注意到如果把变质看成得到并可 ...

随机推荐

  1. JavaScript-创建日志调试对象(面向对象实例)

    参考自http://www.2cto.com/kf/201312/261990.html IC.js文件 自己封装的js类库 /** * * @authors Your Name (you@examp ...

  2. Java中a+=b和a=a+b的区别

    在Java语言中a+=b和a=a+b是有区别的,主要的区别是在运算时精度的问题,当然了-=.*=./=,%=也都是一个道理.这里以a+=b和a=a+b为例做说明. (1)下面以一段Java程序为例,试 ...

  3. 初识shell编程

    1.shell编程之为什么学.怎么学 为什么学shell编程 Linux系统批量管理 提升工作效率,减少重复工作 学好shell编程所需要的基础知识 熟悉使用vim编辑器 熟悉SSH终端 熟练掌握Li ...

  4. Linux之指令 重定向 文件覆盖>和文件追加>>

    指令>和>>区别 指令 > : 如果文件存在,将原来文件的内容覆盖:原文件不存在则创建文件,再添加信息. 指令 >>:不会覆盖原文件内容,将内容追加到文件的尾部. ...

  5. 转://看懂Oracle中的执行计划

    一.什么是Oracle执行计划? 执行计划是一条查询语句在Oracle中的执行过程或访问路径的描述 二.怎样查看Oracle执行计划? 2.1 explain plan for命令查看执行计划 在sq ...

  6. 第1章 初始Docker容器

    1.1 什么是Docker slogan:Build Ship Run Any App Anywher.关键在于Ship,通过把程序和程序运行所需要的环境一起交付. Linux容器技术: Docker ...

  7. python3 二分法查找

    '''二分法查找有序列表掐头去尾取中间查找列表中xx在不在列表中,在,则返回索引值'''# lst = [1, 4, 6, 8, 9, 21, 23, 26, 35, 48, 49, 54, 67, ...

  8. SpringBoot标准Properties

    # =================================================================== # COMMON SPRING BOOT PROPERTIE ...

  9. C++笔记-数组指针/二维数组转换指针

    参考资料: 1. 作者 BensonLaur  :https://www.cnblogs.com/BensonLaur/p/6367077.html 2. https://blog.csdn.net/ ...

  10. 三:OVS+GRE之完整网络流程

    知识点一:linux网桥提供安全组 知识点二:每新建一个网络,在网络节点都会新建一个namespace,只要为该网络建立子网,那么该namespace里就新增dhcp来为该子网分配ip,也可以为该网络 ...