数字三角形加强版,费马小定理求逆元,快速幂

Problem - 1540 (nefu.edu.cn) 

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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值