uoj316【NOI2017】泳池
题目链接
\(S=k\)可以拆成\(S\le k\)减去\(S\le k-1\)。用\((i,j)\)表示第i行第j列。
设\(g(i,j)\)表示前i行前j列都安全其他未知满足条件的概率,\(h(i,j)\)表示前i行前j列是安全的但是\((i+1,j)\)是危险的,其他未知,满足条件的概率。当\(i*j>k\)时两个数组的值都是0。
\(g(i,j)\)的转移可以在\(i+1\)行枚举最右的危险格子来转移:\(g(i,j)=\sum_{k=0}^jh(i,k)*g(i+1,j-k)\)。\(h(i,j)\)同理枚举\(i+1\)行除了\((i+1,j)\)以外的最右的危险格子来转移:\(h(i,j)=\sum_{k=0}^{j-1}h(i,k)*g(i+1,j-k-1)*(1-q)*q^i\),这里dp的复杂度是\(\sum_{i}(\frac{k}{i})^2=O(k^2)\)的。
然后令\(f(i)\)表示前i列的最大矩形\(\le k\)的概率,转移时枚举第一行最长的连续安全区的长度(为\(j-1\)):\(f(i)=\sum_{j=1}^{k+1}f(i-j)*g(1,j-1)*(1-q)\),注意\(i\le k\)时还要从\(g(1,i)\)转移,因为可能它就是第一个连续的安全区。
这是常系数线性递推,k只有1000,可以在\(O(k^2logn)\)的时间内完成,考虑\(f_i=\sum_{j=1}^kf_{i-j}*a_j\)这样一个递推公式,有一个定理是说设这个矩阵的特征多项式为\(g(\lambda)\),(对于一般的矩阵\(g(\lambda)=|\lambda I-A|\),而这个矩阵\(g(\lambda)=\lambda^k-a_1\lambda^{k-1}-...-a_{k-1}\lambda-a_k\)),那么\(g(A)=0\)。因此\(A^k=a_1A^{k-1}+...+a_k\)也就是说\(A^k\)可以用\(A^{k-1}...A^0\)线性表示出来,然后假如我们可以用那k个矩阵线性表示出\(A^i\),那么\(A^i\)乘上\(A\)后再把多出来的\(A^k\)项用那个定理拆掉,所以对于任意的\(A^i\)都可以用\(A^{k-1}...A^0\)线性表示出来。
我们预处理\(A^k\)~\(A^{2k-2}\)的线性表示,两个矩阵相乘相当于两个k-1次多项式相乘,乘出来大于k-1次方的项就拆掉。
最后,设\(A^n=b_0A_0+b_1A_1+...+b_{k-1}A_{k-1}\),由于我们要求\(A^n*X\)的某一项的值,即\(b_0A_0X+b_1A_1X+...+b_{k-1}A_{k-1}X\)的那一项的值,\(k^2\)暴力算出\(A_0\)到\(A_{k-1}\)的值即可。
复杂度\(O(k^2logn)\),其实两部分都可以进一步优化。
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<vector>
#include<algorithm>
#include<cmath>
#define P puts("lala")
#define cp cerr<<"lala"<<endl
#define ln putchar('\n')
#define pb push_back
#define fi first
#define se second
using namespace std;
inline int read()
{
char ch=getchar();int g=1,re=0;
while(ch<'0'||ch>'9') {if(ch=='-')g=-1;ch=getchar();}
while(ch<='9'&&ch>='0') re=(re<<1)+(re<<3)+(ch^48),ch=getchar();
return re*g;
}
typedef long long ll;
typedef pair<int,int> pii;
const int mod=998244353;
const int N=1050;
ll qpow(ll a,int n)
{
ll ans=1;
for(;n;n>>=1,a=a*a%mod) if(n&1) ans=ans*a%mod;
return ans;
}
int m[N<<1][N],C[N<<1];
void mul(int *a,int *b,int k)
{
for(int i=0;i<=(k-1<<1);++i) C[i]=0;
for(int i=0;i<k;++i) for(int j=0;j<k;++j) C[i+j]=(C[i+j]+1ll*a[i]*b[j])%mod;
for(int i=k;i<=(k-1<<1);++i) if(C[i])
for(int j=0;j<k;++j) C[j]=(C[j]+1ll*m[i][j]*C[i])%mod;
for(int i=0;i<k;++i) a[i]=C[i];
}
int f[N<<1],g[N][N],h[N][N],a[N];
int q,pwq[N],A[N<<1],S[N<<1];
int solve(int K,int n)
{
if(!K) return qpow((1-q+mod)%mod,n);
memset(g,0,sizeof(g)); memset(h,0,sizeof(h));
memset(f,0,sizeof(f)); memset(a,0,sizeof(a));
memset(m,0,sizeof(m)); memset(A,0,sizeof(A));
memset(S,0,sizeof(S));
g[K][1]=1ll*pwq[K]*(1-q+mod)%mod;
for(int i=1;i<=K;++i) g[i][0]=1,h[i][0]=1;
for(int i=K-1;i>=1;--i)
{
for(int j=1;j*i<=K;++j)
{
for(int k=0;k<j;++k)
h[i][j]=(h[i][j]+1ll*h[i][k]*g[i+1][j-k-1]%mod*pwq[i]%mod*(1-q+mod))%mod;
for(int k=0;k<=j;++k)
g[i][j]=(g[i][j]+1ll*g[i+1][j-k]*h[i][k])%mod;
}
}
K++;
for(int i=1;i<=K;++i) a[i]=1ll*g[1][i-1]*(1-q+mod)%mod;
f[0]=1;
for(int i=1;i<K;++i)
{
for(int j=1;j<=i;++j) f[i]=(f[i]+1ll*f[i-j]*a[j])%mod;
f[i]=(f[i]+g[1][i])%mod;//!!!
}
//for(int i=K;i<=n;++i) for(int j=1;j<=K;++j) f[i]=(f[i]+1ll*f[i-j]*a[j])%mod;
//return f[n];
for(int i=0;i<K;++i) m[K][i]=a[K-i];
for(int i=K+1;i<=(K-1<<1);++i)
{
for(int j=1;j<=K;++j) m[i][j]=m[i-1][j-1];
for(int j=0;j<K;++j) m[i][j]=(m[i][j]+1ll*m[i][K]*a[K-j])%mod;
m[i][K]=0;
}
S[0]=1; A[1]=1;
for(;n;n>>=1,mul(A,A,K)) if(n&1) mul(S,A,K);
int fn=0;
for(int i=0;i<K;++i) fn=(fn+1ll*f[i]*S[i])%mod;
return fn;
}
int K,n;
int main()
{
#ifndef ONLINE_JUDGE
freopen("pool.in","r",stdin);freopen("pool.out","w",stdout);
#endif
n=read(); K=read(); q=1ll*read()*qpow(read(),mod-2)%mod;
pwq[0]=1;
for(int i=1;i<=K;++i) pwq[i]=1ll*pwq[i-1]*q%mod;
printf("%d\n",(solve(K,n)-solve(K-1,n)+mod)%mod);
return 0;
}
uoj316【NOI2017】泳池的更多相关文章
- [NOI2017]泳池——概率DP+线性递推
[NOI2017]泳池 实在没有思路啊~~~ luogu题解 1.差分,转化成至多k的概率减去至多k-1的概率.这样就不用记录“有没有出现k”这个信息了 2.n是1e9,感觉要递推然后利用数列的加速技 ...
- BZOJ4944: [Noi2017]泳池
BZOJ4944: [Noi2017]泳池 题目背景 久莲是个爱玩的女孩子. 暑假终于到了,久莲决定请她的朋友们来游泳,她打算先在她家的私人海滩外圈一块长方形的海域作为游泳场. 然而大海里有着各种各样 ...
- 【BZOJ4944】[NOI2017]泳池(线性常系数齐次递推,动态规划)
[BZOJ4944][NOI2017]泳池(线性常系数齐次递推,动态规划) 首先恰好为\(k\)很不好算,变为至少或者至多计算然后考虑容斥. 如果是至少的话,我们依然很难处理最大面积这个东西.所以考虑 ...
- [NOI2017]泳池
题目描述 有一个长为\(n\),高为1001的网格,每个格子有\(p\)的概率为1,\((1-p)\)的概率0,定义一个网格的价值为极大的全一矩形,且这个矩形的底要贴着网格的底,求这个网格的价值为\( ...
- Luogu3824 [NOI2017]泳池 【多项式取模】【递推】【矩阵快速幂】
题目分析: 用数论分块的思想,就会发现其实就是连续一段的长度$i$的高度不能超过$\lfloor \frac{k}{i} \rfloor$,然后我们会发现最长的非$0$一段不会超过$k$,所以我们可以 ...
- [学习笔记]Cayley-Hilmiton
Cayley–Hamilton theorem - Wikipedia 其实不是理解很透彻,,,先写上 简而言之: 是一个知道递推式,快速求第n项的方法 k比较小的时候可以用矩阵乘法 k是2000,n ...
- NOI2010~NOI2018选做
[NOI2010] [NOI2010]海拔 高度只需要0/1,所以一个合法方案就是一个割,平面图求最小割. [NOI2010]航空管制 反序拓扑排序,每次取出第一类限制最大的放置,这样做答案不会更劣. ...
- UOJ#316. 【NOI2017】泳池
传送门 一道 \(DP\) 好题 设 \(q\) 为一个块合法的概率 套路一恰好为 \(k\) 的概率不好算,算小于等于 \(k\) 的减去小于等于 \(k-1\) 的 那么设 \(f_i\) 表示宽 ...
- LOJ#2304. 「NOI2017」泳池
$n \leq 1e9$底边长的泳池,好懒啊泥萌自己看题吧,$k \leq 1000$.答案对998244353取膜. 现在令$P$为安全,$Q$为危险的概率.刚好$K$是极其不好算的,于是来算$\l ...
随机推荐
- Nginx Rewrite资源重定向
# Rewrite功能配置 # Rewrite功能主要是实现了url重写 # 如:你输入www.jd123.com,你可以通过Rewrite让它重定向到www.jd.com # Rewrite的实现依 ...
- CDO如何盘点算法、推动算法业务增长
在数字经济时代,算法对企业业务增长至关重要,是企业进行数字化转型.构建竞争优势的关键.IT工程师或数据分析师可能会将算法描述为一组由数据操作形成的规则.而从业务价值方面考虑,算法是一种捕获商业机会.提 ...
- 使用 DolphinScheduler 调度 Kylin 构建
本文章经授权转载 Apache Kylin 上游通常有复杂的数据 ETL 过程,如 Hive 入库.数据清洗等:下游有报表刷新,邮件分发等.集成 Apache DolphinScheduler 后,K ...
- CF360E Levko and Game(贪心)
这题贪心停水的,找\(dis1<=dis2\)的点往歇斯底里地砍,砍到没法砍就是. 写博客是为了记录下遇到的神奇bug #include <iostream> #include &l ...
- Excel 名称管理器是什么,并实现一个级联选择框
名称 在 Excel 中,每一个单元格都有自己的名称.表格横向是字母,纵向是数字,组合起来就是一个单元格的名称. A13 所代表的是 A 列,13 行的单元格.把一组单元格组合起来,加上一个名称,在 ...
- Excel 单元格的相对引用和绝对引用
引用方式 单元格的地址由该单元格所在的行号和列标构成,一个引用代表工作表上的一个或者一组单元格,指明公式中数据所在的位置. 编号 消费记录 价格 1 乒乓球 1 2 火腿肠 2 3 乒乓球 1 4 羽 ...
- React报错之You provided a `checked` prop to a form field
正文从这开始~ 总览 当我们在多选框上设置了checked 属性,却没有onChange 处理函数时,会产生"You provided a checked prop to a form fi ...
- Go 语言入门 3-动态数组(slice)的特性及实现原理
go 语言中的动态数组(slice),是基于数组实现的,可以相比数组而言更加的灵活.其他语言的 slice 通常仅是一个 API, 但是 go 语言的 slice 不仅仅是一种操作, 也是一种数据结构 ...
- KingbaseES 实现MYSQL hex/unhex 函数
MySQL 的hex 和 unhex 函数类似于KingbaseES 的encode 和 decoding,实现字符与16进制之间的转换. 一.先看MySQL例子 mysql> select h ...
- Taurus.MVC-Java 版本打包上传到Maven中央仓库(详细过程):1、JIRA账号注册
文章目录: Taurus.MVC-Java 版本打包上传到Maven中央仓库(详细过程):1.JIRA账号注册 Taurus.MVC-Java 版本打包上传到Maven中央仓库(详细过程):2.PGP ...