费马小定理

定义

a a a p p p 互质(即 gcd ⁡ ( a , p ) = 1 \gcd(a,p)=1 gcd(a,p)=1),则:
a p − 1 ≡ 1 ( m o d p ) a^{p-1}\equiv1\pmod p ap11(modp)
根据上述公式我们还可以推出一个公式:
a p − 2 ≡ a − 1 ( m o d p ) a^{p-2}\equiv a^{-1}\pmod p ap2a1(modp)

使用条件: p p p 需为质数。

也就是逆元。

常用来解决有除法且需要取模的问题(除法不能取模)。

应用

P10792 『SpOI - R1』笑起来最帅的小孩

期望+逆元。

比如说我们有 1 1 1 2 2 2 2 2 2 1 1 1,考虑所有情况:

112
112
121
121
211
211

加起来为 888 888 888

数据小的情况可以直接手动例举,但如果数据大了呢?

考虑直接计算每一位的贡献。

比如说第一个 1 1 1 在各位上的贡献为 2 ! 2! 2!,十位为 10 × 2 ! 10\times 2! 10×2!,百位为……

总共贡献: 111 × 2 ! 111\times 2! 111×2!

( 1 0 n − 1 ) × 2 ! (10^n-1)\times 2! (10n1)×2!

n n n 表示数列的长度。

以此类推,所有数字的贡献总和为:
( ∑ i = 1 k x i × l i ) × ( 1 0 n − 1 ) × ( n − 1 ) ! (\sum_{i=1}^k x_i\times l_i)\times (10^n-1)\times (n-1)! (i=1kxi×li)×(10n1)×(n1)!

然后还要对贡献和除以 n ! n! n!,公式为:
( ∑ i = 1 k x i × l i ) × ( 1 0 n − 1 ) n \frac{(\sum_{i=1}^k x_i\times l_i)\times (10^n-1)}{n} n(i=1kxi×li)×(10n1)
接下来用逆元解决就好了。

实现

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int mod=2007072007;
int t,k,x[100005],l[100005];
int kpow(int a,int b){
	int sum=1;
	while(b){
		if(b&1){
			sum=(sum*a)%mod;
		}
		a=(a*a)%mod;
		b/=2;
	}
	return sum;
}
signed main(){
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	for(cin>>t;t;t--){
		cin>>k;
		int n=0,sum=0;
		for(int i=1;i<=k;i++){
			cin>>x[i]>>l[i];
			n=(n+l[i])%mod,sum=(sum+x[i]*l[i])%mod;
		}
		cout<<(((((sum*(kpow(10,n)-1))%mod)*kpow(9,mod-2))%mod)*kpow(n,mod-2))%mod<<'\n';
	}
	return 0;
}
### 费马小定理及其在C++中的实现 费马小定理是一个重要的数论工具,在模运算中有广泛应用。它指出如果 \( p \) 是一个素数,而整数 \( a \) 不被 \( p \) 整除,则有: \[ a^{p-1} \equiv 1 \ (\text{mod}\ p) \] 由此可以推导出 \( a^{-1} \equiv a^{p-2} \ (\text{mod}\ p) \),这使得我们可以通过快速幂算法高效地计算乘法逆元。 以下是基于费马小定理的 C++ 示例代码用于计算模意义下的乘法逆元[^1]: ```cpp #include <iostream> using namespace std; // 快速幂函数:计算 (base^exp) % mod 的结果 long long fast_pow(long long base, long long exp, long long mod) { long long result = 1; while (exp > 0) { if (exp & 1) { // 如果指数当前位为1 result = (__int128(result) * base) % mod; // 防止溢出 } base = (__int128(base) * base) % mod; // 平方并取模 exp >>= 1; // 右移一位 } return result; } // 计算 a 关于模 p 的乘法逆元 long long inverse_modulo(long long a, long long p) { return fast_pow(a, p - 2, p); // 使用费马小定理 } int main() { long long a, p; cout << "Enter the value of 'a' and prime number 'p': "; cin >> a >> p; if (a >= p || __gcd((int)a, (int)p) != 1) { cout << "Inverse does not exist or input is invalid." << endl; } else { long long inv = inverse_modulo(a, p); cout << "The modular multiplicative inverse of " << a << " modulo " << p << " is: " << inv << endl; } return 0; } ``` 上述代码实现了两个主要功能: 1. **快速幂**:`fast_pow` 函数利用二分的思想加速幂次计算。 2. **乘法逆元**:调用 `inverse_modulo` 来返回给定数值关于某个素数模的意义下的逆元[^2]。 #### 应用场景分析 费马小定理的应用广泛存在于多个领域,特别是在涉及模运算的情况下。例如: - 密码学中 RSA 加密系统的公钥和私钥生成过程需要用到大质数上的模逆元操作。 - 组合计数问题可能需要频繁进行分数形式的结果简化,此时也需要借助模逆元来完成除法模拟[^4]。 另外需要注意的是,当题目规模较大或者精度要求较高时,应考虑数据类型的选取以及防止中间变量越界等问题。以上程序采用了 `__int128` 类型以规避部分潜在风险。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值