链接:
https://www.nowcoder.com/acm/contest/73/B
来源:牛客网
来源:牛客网
题目描述
已知
f[1][1]=1,f[i][j]=a*f[i-1][j]+b*f[i-1][j-1](i>=2,1<=j<=i)。
对于其他情况f[i][j]=0
有T组询问,每次给出a,b,n,m,求f[n][m] mod (998244353)
输入描述:
第一行为一个整数T,表示询问个数。 接下来一共T行,每行四个整数a,b,n,m。
输出描述:
一共T行,每行一个整数,表示f[n][m] mod (998244353)
题解:
推导几项便知
f[n][m]=((a+b)^(n-1)式子按a降幂展开的第m项)
套用公式即可。
求逆元时可以用扩展欧几里得求出p[i]*x-mod*y=1的一组解,调整x的值即可。
或用费马小定理求得pow(p[i],mod-2)%mod即可。
扩展欧几里得代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=100007;
const ll mod=998244353;
ll inv[maxn],p[maxn];
ll pow_(ll a,ll b)
{
ll c=1;
while(b)
{
if(b&1)c=c*a%mod;
a=a*a%mod;
b=b/2;
}
return c%mod;
}
ll ex_gcd(ll a,ll b,ll& x,ll& y)
{
ll d=a;
if(b)
{
ex_gcd(b,a%b,y,x);
y-=(a/b)*x;
}
else x=1,y=0;
return d;
}
void init()
{
p[0]=1;
for(ll i=1;i<=100000;i++)p[i]=p[i-1]*i%mod;
for(ll i=0;i<=100000;i++)
{
ll x,y;
ll gcd=ex_gcd(p[i],mod,x,y);
inv[i]=(x+mod)%mod;
}
}
int main()
{
init();
ll T,a,b,n,m;scanf("%lld",&T);
while(T--)
{
scanf("%lld%lld%lld%lld",&a,&b,&n,&m);
n--;
ll c1=pow_(a,n-m+1),c2=pow_(b,m-1);
ll N=((((c1*c2%mod)*p[n]%mod)*inv[m-1]%mod)*inv[n-m+1]%mod);
printf("%lld\n",N);
}
return 0;
}
费马小定理:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=100007;
const ll mod=998244353;
ll inv[maxn],p[maxn];
ll pow_(ll a,ll b)
{
ll c=1;
while(b)
{
if(b&1)c=c*a%mod;
a=a*a%mod;
b=b/2;
}
return c%mod;
}
void init()
{
p[0]=1;
for(ll i=1;i<=100000;i++)p[i]=p[i-1]*i%mod;
for(ll i=0;i<=100000;i++)inv[i]=pow_(p[i],mod-2)%mod;
}
int main()
{
init();
ll T,a,b,n,m;scanf("%lld",&T);
while(T--)
{
scanf("%lld%lld%lld%lld",&a,&b,&n,&m);
n--;
ll c1=pow_(a,n-m+1),c2=pow_(b,m-1);
ll N=((((c1*c2%mod)*p[n]%mod)*inv[m-1]%mod)*inv[n-m+1]%mod);
printf("%lld\n",N);
}
return 0;
}