NC17904. [NOI2017]泳池
描述
输入描述
输入一行四个正整数 N, K, x, y,其中 1 ≤ x < y < 998244353。q 的取值为。
输出描述
输出一行一个整数表示答案在模 998244353 意义下的取值。即设答案化为最简分式后的形式为,其中 a 和 b 的互质。输出整数 x 使得 bx ≡ amod 998244353 且 0 ≤ x < 998244353。可以证明这样的整数 x 是唯一的。
示例1
输入:
10 5 1 2
输出:
342025319
C++11(clang++ 3.9) 解法, 执行用时: 579ms, 内存消耗: 8444K, 提交时间: 2019-01-07 18:56:12
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int K=1009; const ll md=998244353; ll n,k,p,q,x,y; ll f[K][K],g[K],powq[K],ans[K]; ll a[K],b[K]; inline ll qpow(ll a,ll b) { ll ret=1; while(b) { if(b&1) ret=ret*a%md; a=a*a%md; b>>=1; } return ret; } inline void mul(ll *a,ll *b,int k) { static ll c[K*2]; memset(c,0,sizeof(c)); for(int i=0;i<=k;i++) if(a[i]) for(int j=0;j<=k;j++) (c[i+j]+=a[i]*b[j]%md)%=md; for(int i=k*2;i>=k+1;i--) if(c[i]) for(int j=1;j<=k+1;j++) (c[i-j]+=c[i]*g[j]%md)%=md; memcpy(a,c,sizeof(a[0])*(k+1)); } inline ll solve(int k) { if(!k)return qpow(1-q,n); memset(f,0,sizeof(f)); f[k+1][0]=1; for(int j=k;j>=1;j--) { f[j][0]=1; int mi=min((int)n,k/j); int ml=min(mi-1,k/(j+1)); for(int l=0;l<=ml;l++) g[l]=f[j+1][l]*powq[l]%md*p%md; for(int i=1;i<=mi;i++) { int ml=min(i-1,k/(j+1)); for(int l=0;l<=ml;l++) (f[j][i]+=g[l]*f[j][i-1-l]%md)%=md; (f[j][i]+=f[j+1][i]*powq[i])%=md; } } ans[0]=1; for(int i=1;i<=k+1;i++) g[i]=f[1][i-1]*powq[i-1]%md*p%md; for(int i=1;i<=k;i++) { ans[i]=f[1][i]*powq[i]%md; for(int j=1;j<=i;j++) (ans[i]+=ans[i-j]*g[j])%=md; } memset(a,0,sizeof(a)); memset(b,0,sizeof(b)); a[1]=1;b[0]=1; int pcnt=n; while(pcnt) { if(pcnt&1) mul(b,a,k); mul(a,a,k); pcnt>>=1; } ll ret=0; for(int i=0;i<=k;i++) (ret+=b[i]*ans[i]%md)%=md; return ret; } int main() { scanf("%lld%lld%lld%lld",&n,&k,&x,&y); x%=md;y%=md; q=x*qpow(y,md-2)%md; p=(y-x)*qpow(y,md-2)%md; powq[0]=1; for(int i=1;i<=k;i++) powq[i]=powq[i-1]*q%md; printf("%lld\n",(solve(k)-solve(k-1)+md)%md); return 0; }