NOI2017C. 泳池

泳池

题目描述

久莲是个爱玩的女孩子。

暑假终于到了,久莲决定请她的朋友们来游泳,她打算先在她家的私人海滩外圈一块长方形的海域作为游泳场。然而大海里有着各种各样的危险,有些地方水太深,有些地方有带毒的水母出没。她想让圈出来的这一块海域都是安全的。

经过初步分析,这块海域可视为一个底边长为 NNN 米,高为 100110011001 米的长方形网格。其中网格的底边对应着她家的私人海滩,每一个 1 m×1 m1\:\textrm{m}\times1\:\textrm{m}1m×1m 的小正方形都代表着一个单位海域。她拜托了她爸爸明天去测量每一个小正方形是否安全。在得知了信息之后,她要做的就是圈出她想要的游泳场啦。

她心目中理想的游泳场满足如下三个条件:

  • 必须保证安全性。即游泳场中的每一个单位海域都是安全的。
  • 必须是矩形。即游泳场必须是整个网格中的一个 a×ba\times ba×b 的子网格。
  • 必须和海滩相邻。即游泳场的下边界必须紧贴网格的下边界。

例如:当 N=5N = 5N=5 时,若测量的结果如下(因为 100110011001 太大,这儿只画出网格最下面三行的信息,其他部分都是危险的)。

那么她可以选取最下面一行的 1×41\times41×4 的子海域,也可以选择第三列的 3×13\times13×1 的子海域。注意她不能选取最上面一行的 1×51\times51×5 的子海域,因为它没有与海滩相邻。

为了让朋友们玩的开心,她想让游泳场的面积尽可能的大。因此她会选取最下面那一行的 1×41\times41×4 的子海域作为最终方案。

虽然她要明天才能知道每一个单位海域是否安全,但是她现在就想行动起来估计一下她的游泳场面积有多大。经过简单的估计,她假设每一个单位海域都有独立的 qqq 的概率是安全的,1−q1 − q1q 的概率是不安全的。她想要知道她能选择的最大的游泳场的面积__恰好__为 KKK 的概率是多少。

然而久莲对数学并不感兴趣,因此她想让你来帮她计算一下这个数值。

输入格式

输入一行四个正整数 N,K,x,yN,K,x,yN,K,x,y,其中 1≤x1x<y<998244353qqq 的取值为 xy\frac{x}{y}yx

输出格式

输出一行一个整数表示答案在模 998244353998244353998244353 意义下的取值。

即设答案化为最简分式后的形式为 ab\frac{a}{b}ba ,其中 aaabbb 的互质。输出整数 xxx 使得 bx≡amod  998244353bx \equiv a \mod 998244353bxamod9982443530≤x<9982443530 \leq x < 9982443530x<998244353。可以证明这样的整数 xxx 是唯一的。

输入数据 1

10 5 1 2
Copy

输出数据 1

342025319
Copy

数据范围与提示

提示

xp−1≡1(modp)x^{p-1} \equiv 1 \pmod pxp11(modp),其中 ppp 为质数,x∈[1,p)x \in [1,p)x[1,p)

子任务

测试点编号 NNN KKK
1,2 =1=1=1 ≤1000\leq 10001000
3 ≤10\leq 1010 ≤8\leq 88
4 ≤9\leq 99
5 ≤10\leq 1010
6 ≤1000\leq 10001000 ≤7\leq 77
7 ≤8\leq 88
8 ≤9\leq 99
9,10,11 ≤100\leq 100100
12,13,14 ≤1000\leq 10001000
15,16 ≤109\leq 10^9109 ≤10\leq 1010
17,18 ≤100\leq 100100
19,20 ≤1000\leq 10001000
#include

#define For(i,_beg,_end) for(int i=(_beg),i##end=(_end);i<=i##end;++i)
#define Rep(i,_beg,_end) for(int i=(_beg),i##end=(_end);i>=i##end;--i)

template<typename T>T Max(const T &x,const T &y){return x<y?y:x;}
template<typename T>T Min(const T &x,const T &y){return x<y?x:y;}
template<typename T>int chkmax(T &x,const T &y){return x<y?(x=y,1):0;}
template<typename T>int chkmin(T &x,const T &y){return x>y?(x=y,1):0;}
template<typename T>void read(T &x){
	T f=1;char ch=getchar();
	for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
	for(x=0;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
	x*=f;
}

typedef long long LL;
const int N=1010,mod=998244353;
int n,m;
LL a,b,p,q,dp[N][N],g[N][N],pw[N];
LL A[N],f[N<<1];

LL power(LL,LL);
LL Solve(int);

int main(){
	read(n);read(m);read(a);read(b);
	p=a*power(b,mod-2)%mod;q=(mod+1-p)%mod;
	pw[0]=1;
	For(i,1,m) pw[i]=pw[i-1]*p%mod;
	
	printf("%lld\n",(Solve(m)-Solve(m-1)+mod)%mod);
	return 0;
}

LL Solve(int k){
	memset(dp,0,sizeof dp);
	memset(g,0,sizeof g);
	For(i,1,k+2) g[0][i]=dp[0][i]=1;
	For(i,1,k) Rep(j,k/i+1,2){
		For(l,1,i) dp[i][j]=(dp[i][j]+g[l-1][j+1]*g[i-l][j]%mod*pw[l-1]%mod*q)%mod;
		g[i][j]=(g[i][j+1]*pw[i]+dp[i][j])%mod;
	}
	memset(A,0,sizeof A);
	For(i,0,k) A[i+1]=q*g[i][2]%mod*pw[i]%mod;
	memset(f,0,sizeof f);
	f[0]=1;
	For(i,1,k){
		f[i]=g[i][2]*pw[i]%mod;
		For(j,1,i) f[i]=(f[i]+A[j]*f[i-j])%mod;
	}
	k++;
	For(i,k,k<<1) For(j,1,k) f[i]=(f[i]+A[j]*f[i-j])%mod;
	if(n<=k)return f[n];
	int y=n-k,len=1,L=0;
	LL res[N<<2],tmp[N<<2],x[N<<2];
	memset(res,0,sizeof res);
	memset(x,0,sizeof x);
	res[0]=1;x[1]=1;
	for(;y;y>>=1){
		if(y&1){
			For(i,0,L+len) tmp[i]=0;
			For(i,0,L) For(j,0,len) tmp[i+j]=(tmp[i+j]+res[i]*x[j])%mod;
			L+=len;
			Rep(i,L,k) For(j,1,k) tmp[i-j]=(tmp[i-j]+tmp[i]*A[j])%mod;
			chkmin(L,k-1);
			For(i,0,L) res[i]=tmp[i];
		}
		For(i,0,len+len) tmp[i]=0;
		For(i,0,len) For(j,0,len) tmp[i+j]=(tmp[i+j]+x[i]*x[j])%mod;
		len<<=1;
		Rep(i,len,k) For(j,1,k) tmp[i-j]=(tmp[i-j]+tmp[i]*A[j])%mod;
		chkmin(len,k-1);
		For(i,0,len) x[i]=tmp[i];
	}
	LL ans=0;
	For(i,0,k-1) ans=(ans+res[i]*f[i+k])%mod;
	return ans;
}
LL power(LL x,LL y){
	LL res=1;
	for(;y;y>>=1,x=x*x%mod) if(y&1) res=res*x%mod;
	return res;
}

你可能感兴趣的:(C++,NOI,比赛,算法,c++,开发语言,运维,数据库,前端)