逆元 + 快速幂

链接: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)
示例1

输入

2
2 3 3 3
3 1 4 1

输出

9
27

备注:

T<=100000

1<=m<=n<=100000

0<=a,b<=109

 

思路分析 : 对所给的式子进行推导变换,会发现一个规律,就是展开的式子是形入 (a+b)的次方展开式的,然后是让你去求第几项是多少

推的的公式是 C(n-1, m-1)%mod*a^(n-m)%mod*b(m-1)%mod 。比赛的时候现学了一波逆元.....

代码示例:

#define ll long long
const ll mod = 998244353;
const double pi = acos(-1.0);
const int inf = 0x3f3f3f3f;

ll a, b, n, m;
ll pre[123456];

ll extend_gcd(ll a, ll b, ll &x, ll &y) {
    if (b == 0) {
        x = 1, y = 0;
        return a;
    }
    else {
        ll r = extend_gcd(b, a % b, y, x);
        y -= x * (a / b);
        return r;
    }
}
ll inv(ll a, ll n) {
    ll x, y;
    extend_gcd(a, n, x, y);
    x = (x % n + n) % n;
    return x;
} 
  
ll fun(ll x, ll n){
    ll res = 1;
    
    while(n > 0){
        if (n & 1) res *= x; res %= mod;
        x *= x;
        x %= mod;
       n >>= 1; 
    }
    return res%mod;
}

void init() {
    pre[1] = 1; pre[0] = 1;
    for(ll i = 2; i <= 100000; i++){
        pre[i] = pre[i-1]*i;
        pre[i] %= mod;
        //printf("%lld ", pre[i]);
    }    
}

int main() {
    //freopen("in.txt", "r", stdin);
    //freopen("out.txt", "w", stdout);
    int t;
    init();
    //cout << fun(5, 3) << endl;
    //cout << (inv(4, mod)*24)%mod << endl; 
    cin >> t;
    while(t--){
        cin >> a >> b >> n >> m;
        ll ans = fun(a, n-m);
        ans *= fun(b, m-1);
        ans %= mod;
        n--, m--;
        ll f = (pre[m]*pre[n-m])%mod;
        ans *= (pre[n]*inv(f, mod))%mod;
        printf("%lld\n", ans%mod);
    }
    return 0;
}

 

posted @ 2018-03-09 22:37  楼主好菜啊  阅读(269)  评论(0编辑  收藏  举报