Noi2017 泳池
Posted weiyanpeng
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Noi2017 泳池相关的知识,希望对你有一定的参考价值。
首先考虑dp。
不难发现我们大概是对于每一个高度不能有连续的一段长度,并且在下面都安全的时候才计入限制。
\(f[i][j]\)表示长度为i的泳池从高度j开始(i,j)的矩形默认安全,满足最大矩形小于k的概率.
转移相当于做一个类似背包的东西。
然后发现\(j>0\)的时候\(i\le 1000\)(否则dp值为0),然后因为要枚举上一层选择了多少,这个最多到1000。
则,枚举上一个0的位置
\[
f[i][0]=\sum f[j][0] * (f[i-j-1][1] * p^i-j-1*(1-p))
\]
线性递推就没了。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=998244353;
inline int add(int a,int b)a+=b;return a>=mod?a-mod:a;
inline int sub(int a,int b)a-=b;return a<0?a+mod:a;
inline int mul(int a,int b)return (ll)a*b%mod;
inline int qpow(int a,int b)
int ret=1;for(;b;b>>=1,a=mul(a,a))if(b&1)ret=mul(ret,a);return ret;
inline int _inv(int x)return qpow(x,mod-2);
/* math */
int n,k,x,y,p;
const int N=1e3+6;
int f[N][N];
typedef vector<int> poly;
poly F,A,R;
poly mul(poly a,poly b)
poly ret(a.size()+b.size()-1,0);
for(size_t i=0;i<a.size();i++)for(size_t j=0;j<b.size();j++)ret[i+j]=add(ret[i+j],mul(a[i],b[j]));
return ret;
poly Div(poly a,poly b)
int t=b[b.size()-1];
t=_inv(t);
for(size_t i=a.size()-1;i>=b.size()-1;i--)
int temp=mul(a[i],t);
for(size_t pos=i,j=b.size()-1;~j;pos--,j--)
a[pos]=sub(a[pos],mul(temp,b[j]));
a.resize(min(a.size(),b.size()-1));
return a;
inline int solve(int k)
memset(f,0,sizeof(f));
for(int j=0;j<=k+2;j++)f[0][j]=1;
for(int i=1;i<=k;i++)for(int j=k/i;~j;j--)
f[i][j]=mul(qpow(p,i),f[i][j+1]);
for(int k=1,P=sub(1,p);k<=i;k++,P=mul(P,p))
f[i][j]=add(mul(f[k-1][j+1],mul(P,f[i-k][j])),f[i][j]);
F.resize(k+2);
for(int i=0;i<=k;i++)F[i]=mul(mul(sub(p,1),qpow(p,k-i)),f[k-i][1]);
F[k+1]=1;
A=poly(2,0);A[1]=1;
R=poly(1,1);
int K=n;
for(;K;K>>=1)
if(K&1)
R=mul(R,A);
R=Div(R,F);
A=mul(A,A);
A=Div(A,F);
int ret=0;
for(size_t i=0;i<R.size();i++)
ret=add(ret,mul(R[i],f[i][0]));
return ret;
int main()
cin >> n >> k >> x >> y;p=mul(x,_inv(y));
printf("%d\n",sub(solve(k),solve(k-1)));
以上是关于Noi2017 泳池的主要内容,如果未能解决你的问题,请参考以下文章