[NOI2017]泳池

实在没有思路啊~~~

luogu题解

1.差分,转化成至多k的概率减去至多k-1的概率。这样就不用记录“有没有出现k”这个信息了

2.n是1e9,感觉要递推然后利用数列的加速技巧

f[n]表示宽度为n的值,然后枚举最后一个连续高度至少为1的块,dp数组辅助

神仙dp:dp[i][j]表示宽度为i,j的高度出现限制,任意矩形不大于k的概率

设计确实巧妙:宽度利于转移给f,高度利于自己的转移

dp数组转移:枚举第一个到达j的限制的位置,这样,前面部分限制至少是j+1,后面至少是j,中间概率是P^(j-1)*(1-P)

    并且,若i*j<=k,那么新增的就是中间的i*j的矩形,两边都满足的情况下,现在也一定满足

  后缀和优化,限制j的范围,调和级数可以证明状态实际上只有klogk个,转移O(k)

边界:f[0]=1,dp[0][*]=1,注意,*是0~k+2

3.我们现在得到了f的递推式

先递推找到f的前几项

k范围限制不能矩乘

利用[学习笔记]Cayley-Hilmiton

可以倍增加多项式取模

k<=1000可以暴力取模

发现,模数的最高项是1,所以不用逆元!

O(k^2(logn+logk))

代码:

#include<bits/stdc++.h>
#define reg register int
#define il inline
#define numb (ch^'0')
#define int long long
using namespace std;
typedef long long ll;
il void rd(int &x){
char ch;x=;bool fl=false;
while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
for(x=numb;isdigit(ch=getchar());x=x*+numb);
(fl==true)&&(x=-x);
}
namespace Miracle{
const int N=;
const int mod=;
ll a[*N],b[*N],f[*N],yu[*N],ret[*N];
ll dp[*N][*N];
ll mi[*N];
ll n,k,x,y;
ll P;
ll ans;
ll qm(ll x,ll y){
ll ret=;
while(y){
if(y&) ret=ret*x%mod;
x=x*x%mod;
y>>=;
}
return ret;
}
void mul(ll *f,ll *g,ll *mo,int n){
memset(b,,sizeof b);
for(reg i=;i<=n;++i){
for(reg j=;j<=n;++j){
b[i+j]=(b[i+j]+f[i]*g[j]%mod)%mod;
}
}
for(reg i=*n;i>=n;--i){
if(b[i])
for(reg j=;j<=n;++j) b[i+j-n]=(b[i+j-n]+mod-b[i]*mo[j]%mod)%mod;
}
for(reg i=;i<=n;++i) f[i]=b[i],b[i]=;
for(reg i=n+;i<=*n;++i) f[i]=,b[i]=;
}
ll calc(int k){
memset(dp,,sizeof dp);
for(reg i=;i<=k+;++i) dp[][i]=;
for(reg i=;i<=k;++i){
for(reg j=k/i+;j>=;--j){
for(reg l=;l<=i;++l){
dp[i][j]=(dp[i][j]+dp[l-][j+]*dp[i-l][j]%mod*(+mod-P)%mod*mi[j-]%mod)%mod;
}
dp[i][j]=(dp[i][j+]+dp[i][j])%mod;
}
}
for(reg i=;i<=k;++i) a[k-i]=(mod-dp[i][]*(+mod-P)%mod)%mod;
a[k+]=;
memset(f,,sizeof f);
f[]=;
for(reg l=;l<=*k;++l){
for(reg i=;i<=l;++i){
if(l-i->=) f[l]=(f[l]+f[l-i-]*dp[i][]%mod*(+mod-P)%mod)%mod;
else f[l]=(f[l]+dp[i][])%mod;
}
}
if(n<=*k) return f[n];
int y=n;
memset(ret,,sizeof ret);
memset(yu,,sizeof yu);
ret[]=;
yu[]=;
while(y){
if(y&) mul(ret,yu,a,k+);
mul(yu,yu,a,k+);
y>>=;
}
ll bac=;
for(reg i=;i<=k;++i){
bac=(bac+ret[i]*f[i]%mod)%mod;
}
return bac;
}
int main(){
scanf("%lld%lld%lld%lld",&n,&k,&x,&y);
P=x*qm(y,mod-)%mod;
int lp=k;
mi[]=;
for(reg i=;i<=k;++i) mi[i]=mi[i-]*P%mod;
printf("%lld\n",(calc(lp)-calc(lp-)+mod)%mod);
return ;
} }
signed main(){
Miracle::main();
return ;
} /*
Author: *Miracle*
Date: 2019/2/25 16:31:18
*/

总结:
1.DP还是有一点套路可循的,f是枚举最后连续的段,dp是枚举第一个限制到j的位置

2.线性递推的优化方法。

[NOI2017]泳池——概率DP+线性递推的更多相关文章

  1. 【BZOJ4944】【NOI2017】泳池 概率DP 常系数线性递推 特征多项式 多项式取模

    题目大意 有一个\(1001\times n\)的的网格,每个格子有\(q\)的概率是安全的,\(1-q\)的概率是危险的. 定义一个矩形是合法的当且仅当: 这个矩形中每个格子都是安全的 必须紧贴网格 ...

  2. BZOJ5017 [Snoi2017]炸弹[线段树优化建边+scc缩点+DAG上DP/线性递推]

    方法一: 朴素思路:果断建图,每次二分出一个区间然后要向这个区间每个点连有向边,然后一个环的话是可以互相引爆的,缩点之后就是一个DAG,求每个点出发有多少可达点. 然后注意两个问题: 上述建边显然$n ...

  3. codeforces 696C PLEASE 概率dp+公式递推+费马小定理

    题意:有3个杯子,排放一行,刚开始钥匙在中间的杯子,每次操作,将左右两边任意一个杯子进行交换,问n次操作后钥匙在中间杯子的概率 分析:考虑动态规划做法,dp[i]代表i次操作后的,钥匙在中间的概率,由 ...

  4. HDU 5863 cjj's string game ( 16年多校10 G 题、矩阵快速幂优化线性递推DP )

    题目链接 题意 : 有种不同的字符,每种字符有无限个,要求用这k种字符构造两个长度为n的字符串a和b,使得a串和b串的最长公共部分长度恰为m,问方案数 分析 : 直觉是DP 不过当时看到 n 很大.但 ...

  5. HDU - 6172:Array Challenge (BM线性递推)

    题意:给出,三个函数,h,b,a,然后T次询问,每次给出n,求sqrt(an); 思路:不会推,但是感觉a应该是线性的,这个时候我们就可以用BM线性递推,自己求出前几项,然后放到模板里,就可以求了. ...

  6. LG5487 【模板】线性递推+BM算法

    [模板]线性递推+BM算法 给出一个数列 \(P\) 从 \(0\) 开始的前 \(n\) 项,求序列 \(P\) 在\(\bmod~998244353\) 下的最短线性递推式,并在 \(\bmod~ ...

  7. BM求线性递推模板(杜教版)

    BM求线性递推模板(杜教版) BM求线性递推是最近了解到的一个黑科技 如果一个数列.其能够通过线性递推而来 例如使用矩阵快速幂优化的 DP 大概都可以丢进去 则使用 BM 即可得到任意 N 项的数列元 ...

  8. 利用Cayley-Hamilton theorem 优化矩阵线性递推

    平时有关线性递推的题,很多都可以利用矩阵乘法来解决. 时间复杂度一般是O(K3logn)因此对矩阵的规模限制比较大. 下面介绍一种利用利用Cayley-Hamilton theorem加速矩阵乘法的方 ...

  9. 矩阵乘法&矩阵快速幂&矩阵快速幂解决线性递推式

    矩阵乘法,顾名思义矩阵与矩阵相乘, 两矩阵可相乘的前提:第一个矩阵的行与第二个矩阵的列相等 相乘原则: a b     *     A B   =   a*A+b*C  a*c+b*D c d     ...

随机推荐

  1. 基于DDD的.NET开发框架ABP实例,多租户 (Saas)应用程序,采用.NET MVC, Angularjs, EntityFramework-介绍

    介绍 基于ABPZERO的多租户 (Saas)应用程序,采用ASP.NET MVC, Angularjs-介绍 ASP.NET Boilerplate作为应用程序框架. ASP.NET MVC和ASP ...

  2. ASP.NETZERO 开发者指南-目录篇

    前面的话 此教程适用于 ASP.NET MVC 5.x & Angularjs 1.x  的ABP框架(收费需要授权) 所以有能力的朋友还是希望你们多多支持 土牛.购买链接:https://w ...

  3. 从源码的角度看 React JS 中批量更新 State 的策略(下)

    这篇文章我们继续从源码的角度学习 React JS 中的批量更新 State 的策略,供我们继续深入学习研究 React 之用. 前置文章列表 深入理解 React JS 中的 setState 从源 ...

  4. Webpack 2 视频教程

    这是我免费发布的高质量超清「Webpack 2 视频教程」. Webpack 作为目前前端开发必备的框架,Webpack 发布了 2.0 版本,此视频就是基于 2.0 的版本讲解的. 这个基本就是目前 ...

  5. linux alias 别名设置【转载】

    功能说明:设置指令的别名. 语 法:alias[别名]=[指令名称] 形如: alias cp=“cp -i” : 补充说明:用户可利用alias,自定指令的别名.若仅输入alias,则可列出目前所有 ...

  6. UVA - 116 Unidirectional TSP 多段图的最短路 dp

    题意 略 分析 因为字典序最小,所以从后面的列递推,每次对上一列的三个方向的行排序就能确保,数字之和最小DP就完事了 代码 因为有个地方数组名next和里面本身的某个东西冲突了,所以编译错了,后来改成 ...

  7. 11-Python3从入门到实战—基础之生成器和迭代器

    Python从入门到实战系列--目录 切片 Python提供切片(Slice)操作符用来获取列表.元组等数据中的部分元素:如,读取列表 list[m:n]:表示获取m-n区间的元素 list[m:n: ...

  8. Golang 入门~~基础知识

    变量声明 //通用形式,指定变量名,变量类型,变量值 var name int = 99 fmt.Println(name) //指定变量名,以及变量类型,未指定值的时候默认是类型零值 var age ...

  9. Centos7 yum安装Chrome浏览器

    一.创建yum源文件 cd /etc/yum.repo.d/ touch google-chrome.repo 二.输入yum源信息 [google-chrome] name=google-chrom ...

  10. 设计模式之工厂模式(c++)

    问题描述 在面向对象系统设计中经常可以遇到以下的两类问题:1)为了提高内聚(Cohesion)和松耦合(Coupling),我们经常会抽象出一些类的公共接口以形成抽象基类或者接口.这样我们可以通过声明 ...