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

题解

首先,我们将答案转化成最大矩形大小 \(\leq k\) 的概率 减去 \(\leq k-1\) 的概率。

然后我们考虑 DP。

设 \(dp[i][j]\) 表示矩形宽度为 \(j\) ,当前已知最底下 \(i\) 行是安全的,在这个情况下,最大安全区域 \(\leq k\) 或 \(\leq k-1\) 的概率。

状态的转移分两种:一种是第 \(i+1\) 层全部安全,一种是枚举第 \(i+1\) 层的第一个不安全点。

\[dp[i][j] = q ^ {j} dp[i+1][j] + \sum_{k=1}^j (1-q)q^{k-1} dp[i+1][k-1] \cdot dp[i][j-k]
\]

至此,我们得到了 70 分的做法。

接下来进入鬼畜时间:

通过打(bai)表(du),我们可以得知,数列 \(dp[0][1],dp[0][2],\cdots ,dp[0][n]\) 的最短线性递推式很短,几千就够了。

大力上一波 BM 求个递推式,然后大力套用 Cayley-Hamilton定理 求出第 \(n\) 项即可。

代码

#include <bits/stdc++.h>
#define clr(x) memset(x,0,sizeof x)
#define For(i,a,b) for (int i=(a);i<=(b);i++)
#define Fod(i,b,a) for (int i=(b);i>=(a);i--)
#define fi first
#define se second
#define pb(x) push_back(x)
#define mp(x,y) make_pair(x,y)
#define outval(x) printf(#x" = %d\n",x)
#define outtag(x) puts("---------------"#x"---------------")
#define outarr(a,L,R) printf(#a"[%d..%d] = ",L,R);\
For(_x,L,R)printf("%d ",a[_x]);puts("")
using namespace std;
typedef long long LL;
LL read(){
LL x=0,f=0;
char ch=getchar();
while (!isdigit(ch))
f|=ch=='-',ch=getchar();
while (isdigit(ch))
x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
return f?-x:x;
}
const int N=2005*2,mod=998244353;
int Pow(int x,int y){
int ans=1;
for (;y;y>>=1,x=(LL)x*x%mod)
if (y&1)
ans=(LL)ans*x%mod;
return ans;
}
void Add(int &x,int y){
if ((x+=y)>=mod)
x-=mod;
}
void Del(int &x,int y){
if ((x-=y)<0)
x+=mod;
}
int n,k,p,ip;
int getp(){
int x=read(),y=read();
return (LL)x*Pow(y,mod-2)%mod;
}
int pwp[N];
int dp[N][N];
vector <int> BM(int *a,int n){
static vector <int> R[N];
static int Fail[N],d[N];
clr(Fail),clr(d);
R[0].clear();
int c=0;
For(i,1,n){
d[i]=a[i];
For(j,0,(int)R[c].size()-1)
Del(d[i],(LL)R[c][j]*a[i-j-1]%mod);
if (d[i]==0)
continue;
Fail[c]=i;
if (c==0){
R[++c].clear();
R[c].resize(i,0);
continue;
}
int id=c-1;
For(j,0,c-1)
if (i-Fail[j]+(int)R[j].size()<i-Fail[id]+(int)R[id].size())
id=j;
int tmp=(LL)d[i]*Pow(d[Fail[id]],mod-2)%mod;
R[c+1]=R[c];
R[c+1].resize(max((int)R[c].size(),i-Fail[id]+(int)R[id].size()),0);
Add(R[c+1][i-Fail[id]-1],tmp);
For(j,0,(int)R[id].size()-1)
Del(R[c+1][i-Fail[id]+j],(LL)tmp*R[id][j]%mod);
c++;
}
return R[c];
}
void Mul(int *x,int *y,int *a,int n){
static int z[N];
clr(z);
For(i,0,n-1)
For(j,0,n-1)
Add(z[i+j],(LL)x[i]*y[j]%mod);
Fod(i,n*2-2,n)
if (z[i])
For(j,1,n)
Add(z[i-j],(LL)a[j]*z[i]%mod);
For(i,0,n-1)
x[i]=z[i];
}
int CH(int *a,int *b,int n,int k){
static int c[N],x[N];
clr(c),clr(x),c[0]=x[1]=1;
if (n==1)
x[1]=0,x[0]=a[1];
int y=k;
for (;y;y>>=1,Mul(x,x,a,n))
if (y&1)
Mul(c,x,a,n);
int ans=0;
For(i,0,n-1)
Add(ans,(LL)b[i]*c[i]%mod);
return ans;
}
int calc(int *a,int n,int k){
vector <int> vb=BM(a,n);
static int b[N];
clr(b);
n=vb.size();
For(i,0,n-1)
b[i+1]=vb[i];
return CH(b,a,n,k);
}
int Solve(int k){
int lim=min(n,2000);
clr(dp);
For(i,0,k+1)
dp[i][0]=1;
Fod(i,k,0)
for (int j=1;j<=lim&&j*i<=k;j++){
Add(dp[i][j],(LL)dp[i+1][j]*pwp[j]%mod);
For(t,1,j)
Add(dp[i][j],(LL)dp[i+1][t-1]*pwp[t-1]%mod*ip%mod*dp[i][j-t]%mod);
}
if (n<=lim)
return dp[0][n];
return calc(dp[0],lim,n);
}
int main(){
n=read(),k=read(),p=getp(),ip=(mod+1-p)%mod;
pwp[0]=1;
For(i,1,min(n,4000))
pwp[i]=(LL)pwp[i-1]*p%mod;
printf("%d\n",(Solve(k)-Solve(k-1)+mod)%mod);
return 0;
}

UOJ#316. 【NOI2017】泳池 动态规划,Berlekamp-Massey,Cayley-Hamilton定理的更多相关文章

  1. 【BZOJ4944】[NOI2017]泳池(线性常系数齐次递推,动态规划)

    [BZOJ4944][NOI2017]泳池(线性常系数齐次递推,动态规划) 首先恰好为\(k\)很不好算,变为至少或者至多计算然后考虑容斥. 如果是至少的话,我们依然很难处理最大面积这个东西.所以考虑 ...

  2. [NOI2017]泳池——概率DP+线性递推

    [NOI2017]泳池 实在没有思路啊~~~ luogu题解 1.差分,转化成至多k的概率减去至多k-1的概率.这样就不用记录“有没有出现k”这个信息了 2.n是1e9,感觉要递推然后利用数列的加速技 ...

  3. BZOJ4944: [Noi2017]泳池

    BZOJ4944: [Noi2017]泳池 题目背景 久莲是个爱玩的女孩子. 暑假终于到了,久莲决定请她的朋友们来游泳,她打算先在她家的私人海滩外圈一块长方形的海域作为游泳场. 然而大海里有着各种各样 ...

  4. UOJ#316. 【NOI2017】泳池

    传送门 一道 \(DP\) 好题 设 \(q\) 为一个块合法的概率 套路一恰好为 \(k\) 的概率不好算,算小于等于 \(k\) 的减去小于等于 \(k-1\) 的 那么设 \(f_i\) 表示宽 ...

  5. BZOJ 4945 UOJ #317 NOI2017 游戏 2-SAT 拓扑排序

    http://uoj.ac/problem/317 https://www.lydsy.com/JudgeOnline/problem.php?id=4945 我现在的程序uoj的额外数据通过不了,b ...

  6. [NOI2017]泳池

    题目描述 有一个长为\(n\),高为1001的网格,每个格子有\(p\)的概率为1,\((1-p)\)的概率0,定义一个网格的价值为极大的全一矩形,且这个矩形的底要贴着网格的底,求这个网格的价值为\( ...

  7. Luogu3824 [NOI2017]泳池 【多项式取模】【递推】【矩阵快速幂】

    题目分析: 用数论分块的思想,就会发现其实就是连续一段的长度$i$的高度不能超过$\lfloor \frac{k}{i} \rfloor$,然后我们会发现最长的非$0$一段不会超过$k$,所以我们可以 ...

  8. Berlekamp Massey算法求线性递推式

    BM算法求求线性递推式   P5487 线性递推+BM算法   待AC.   Poor God Water   // 题目来源:ACM-ICPC 2018 焦作赛区网络预赛 题意   God Wate ...

  9. 【动态规划】拦截导弹_dilworth定理_最长递增子序列

    问题 K: [动态规划]拦截导弹 时间限制: 1 Sec  内存限制: 256 MB提交: 39  解决: 10[提交][状态][讨论版] 题目描述 张琪曼:“老师,修罗场是什么?” 墨老师:“修罗是 ...

随机推荐

  1. 前端开发 vue,angular,react框架对比1

    转载自:https://www.cnblogs.com/hubgit/p/6633214.html 首先,我们先了解什么是MVX框架模式? MVX框架模式:MVC+MVP+MVVM 1.MVC:Mod ...

  2. 1.1 文档PUT内部原理

    文档更新原理:       PUT 一条数据的时候,如果是全量替换,ES并不会覆盖原来的文档,而是新创建一个文档,并将version+1,原文档标记为deleted,不会立刻物理删除.ES会在集群的d ...

  3. 并发编程-线程-死锁现象-GIL全局锁-线程池

    一堆锁 死锁现象 (重点) 死锁指的是某个资源被占用后,一直得不到释放,导致其他需要这个资源的线程进入阻塞状态. 产生死锁的情况 对同一把互斥锁加了多次 一个共享资源,要访问必须同时具备多把锁,但是这 ...

  4. Keepalived简单理解

    Keepalived Keepalived是一个基于VRRP协议来实现的LVS服务高可用方案,可以利用其来避免单点故障.一个LVS服务会有2台服务器运行Keepalived,一台为主服务器(MASTE ...

  5. 【转载】Javascript使用Math.floor方法向下取整

    在Javascript的数值运算中,很多时候需要对最后计算结果向下取整,Math.floor是javascript中对计算结果向下取整的函数,它总是将数值向下舍入为最接近的整数.此外Math.ceil ...

  6. CSS标签选择器&类选择器

    基本选择器包括标签选择器.类选择器和ID选择器三类,其他选择器都是在这三类选择器的基础上组合形成 ##标签选择器 示例: <style type="text/css"> ...

  7. Qt QListWidget

    以下代码是 List Widget 添加数据项的代码,一般放在构造函数即可. /*********************添加数据项*********************/ QIcon icon1 ...

  8. Tomcat启动时一闪而过,看不多错误信息解决方案

    转自:https://wangxh89.iteye.com/blog/1824806 有时Tomcat的启动窗口一闪而过,根本就看不出启动过程中发生了什么错误.这中间的原因有好多种,最常见的解决办法就 ...

  9. 设置redis开机自动启动

    注意:win7执行命令前面可不需要加路径,win10必须要加路径 命令: redis-server --service-install redis.windows.conf 执行完成之后,打开服务管理 ...

  10. MySQL Binlog--事务日志和BINLOG落盘参数对磁盘IO的影响

    参数说明 innodb_flush_log_at_trx_commit和sync_binlog 两个参数是控制MySQL 磁盘写入策略以及数据安全性的关键参数,不同参数设置对磁盘IO影响不同. 参数i ...