数字三角形加强版,费马小定理求逆元,快速幂
Contest (nefu.edu.cn)
Description
一个无限行的数字三角形,第 i 行有 i 个数。第一行的第一个数是 1 ,其他的数满足如下关系:如果用 F[i][j] 表示第 i 行的第 j 个数,那么 F[i][j]=A∗F[i−1][j]+B∗F[i−1][j−1] (不合法的下标的数为 0 )。 当 A=2,B=3 时的数字三角形的前 5 行为: 1 2 3 4 12 9 8 36 54 27 16 96 216 216 81 现在有 T 次询问,求 A=a,B=b 时数字三角形的第 n 行第 m 个数的值模 10^9+9 的结果。
Input
第一行为一个整数 T 。 接下一共 T 行,每行四个整数 a,b,n,m
Output
一共 T 行,每行一个整数,表示那个位置上的数的值。
Sample Input
2 2 3 3 3 3 1 4 1
Sample Output
9 27
Hint
n,t<=1e5;1<=m<=n; 0<=a,b<=1e9;
解析:费马小定理求逆元,快速幂
观察题目所给样例,我们会发现在若问:
A,B,n,m;
则答案为:C(n-1,m-1)*n^(n-m)*m^(m-1)
即为:(n-1)!/((m-1)!*(n-m)!)*n^(n-m)*m^(m-1);
这里的难点在于取模没有乘法分配律:
但如果分母不取模一定会爆
所以这里我们就需要求分母的乘法逆元;
这里使用费马小定理来求乘法逆元
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<utility>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
using namespace std;
typedef long long LL;
const int N = 1e5 + 5;
const LL mod = 1e9 + 9;
int A, B, n, m;
LL f[N], ft[N];
LL F(LL a, LL pp, LL p) {
LL ret = 1, t = a;
while (pp) {
if (pp & 1)ret = (ret * t) % p;
pp >>= 1;
t = (t * t) % p;
}
return ret;
}
void init() {
f[0] = 1;
for (int i = 1; i <= 1e5; i++) {
f[i] = (f[i - 1] * i) % mod;
}
}
int main() {
int T;
scanf("%d", &T);
init();
while (T--) {
scanf("%d%d%d%d", &A, &B, &n, &m);
LL ans = 1;
ans = (ans * F(A, n - m, mod) % mod) % mod;
ans = (ans * F(B, m - 1, mod) % mod) % mod;
ans = (ans * f[n - 1]) % mod;
ans = (ans * F(f[m - 1], mod - 2, mod) % mod) % mod;
ans = (ans * F(f[n - m], mod - 2, mod) % mod) % mod;
printf("%lld\n", ans);
}
return 0;
}