Wannafly挑战赛11 B、白兔的式子

题目链接:https://www.nowcoder.com/acm/contest/73/B

flag:  找规律 + 逆元解A/B%Mod

找规律不难发现: 

        *   m>n ,f[n][m] = 0;

        *   m<=n, f[n][m] = C(n-1,m-1)*a^(n-m)*b^(m-1);


主要是C(n-1,m-1)%Mod求有技巧:

          C(n-1,m-1)%Mod

       = (n-1)!/[(m-1)!*(n-m)!]%Mod

       即找出(m-1)! 、(n-m)!的逆元g[m-1]、g[n-m]

       = (n-1)!/[g[m-1]*g[n-m]]%Mod

即我们需要预处理出:求出所有i!的逆元与本身(0<=i<=1e5); 


而  f[i]定义为i!,g[i]定义为i!的逆元;

我们可以得出:g[i]=g[i+1]*(i+1)%Mod; ( g[i+1]*(i+1)!≡(g[i+1]*(i+1))*i!≡ 1(mod Mod) ,即g[i+1]*(i+1)=g[i]; )

所以我们仅需要求出g[100000],其它均可递推出;


求g[100000],因为Mod=998244353为质数,所以可以非常好用欧拉函数解逆元:x^(Mod-1)≡x*x^≡≡1(mod Mod)

即g[x]=x^(Mod-1) ,可以用快速矩阵幂来处理!


#include <iostream>
#include <stdio.h>
#include <string.h>
#include <queue>
#include <vector>
#include <math.h>
#define llt long long
#define Maxn 200010
#define Mod 998244353
using namespace std;

llt f[Maxn],g[Maxn];

llt F(llt x,llt a){
    if(a==0)return 1;
    if(a==1)return x;
    llt ans=F(x,a/2);
    if(a%2==0)return ans*ans%Mod;
    return ans*ans%Mod*x%Mod;
}

void init(){

    f[0]=f[1]=1;
    for(int i=2;i<=200000;++i){
        f[i]=f[i-1]*i%Mod;
    }
    g[100000]=F(f[100000],Mod-2);
    g[0]=1;
    for(int i=100000-1;i>=1;--i)
        g[i]=g[i+1]*(i+1)%Mod;
}

int main(){
    int T;
    init();
    scanf("%d",&T);
    while(T--){
        llt a,b,m,n;
        scanf("%lld%lld%lld%lld",&a,&b,&n,&m);
        if(m>n)printf("0\n");
        else{
            
            printf("%lld\n", f[n-1]*g[m-1]%Mod*g[n-m]%Mod*F(a,n-m)%Mod*F(b,m-1)%Mod);
        }
    }


    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值