费马小定理

费马小定理

费马是个很出名的大佬,比较熟悉就是费马大定理。今天我们来谈谈费马的小定理。这是数论里面一个非常重要的定理,在高中的数学联赛或者是信息学竞赛,以及大学的ACM竞赛都是很重要的一个定理。那么今天就来科普一下吧。

定理讲诉

费马小定理是这样的,对于整数 a a a,和质数 p p p,如果 a a a p p p互质,那么有 a p − 1 ≡ 1 ( m o d p ) a^{p-1} \equiv1(mod p) ap11(modp),欧拉将其上升为 a p ≡ a ( m o d p ) a^p \equiv a(modp) apa(modp).
关于定理的证明,笔者这边写个我高中时会的一种方法(其实是到现在我也就只会这种方法qaq) .

证明

对于质数 p p p, 我们有序列 1 , 2 , 3 , ⋯ p − 1 1,2,3,\cdots p-1 123p1, 显然序列中的任何数均与 p p p互质,又 a a a p p p互质,那么可以得出对于任意 i , j ( i ≠ j ) , a ⋅ i ≡ a ⋅ j ( m o d p ) i,j(i\neq j) ,a\cdot i \equiv a\cdot j(mod p) i,j(i̸=j),aiaj(modp)不成立,这个可以用反证法证明,即有 a ⋅ ( i − j ) ≡ 0 ( m o d p ) a \cdot(i-j) \equiv 0(modp) a(ij)0(modp)这与 a a a p p p互质时矛盾的,根据这点我们可以构造
( a ⋅ 1 ) ( a ⋅ 2 ) ⋯ ( a ⋅ ( p − 1 ) ) ≡ 1 ⋅ 2 ⋅ p − 1 ( m o d p ) (a \cdot 1)(a \cdot 2) \cdots (a\cdot (p-1)) \equiv 1 \cdot 2 \cdot p-1(modp) (a1)(a2)(a(p1))12p1(modp) = > a p − 1 ⋅ ( p − 1 ) ! ≡ ( p − 1 ) ! ( m o d p ) =>a^{p-1}\cdot(p-1)!\equiv(p-1)!(modp) =>ap1(p1)!(p1)!(modp) = > a p − 1 ≡ 1 ( m o d p ) =>a^{p-1}\equiv1(modp) =>ap11(modp)

知道证明之后我们就来看看怎么实战吧,做题当中通常我们还得知道膜逆元这东西,膜,题目通常会让我们求 a b ( m o d p ) \frac{a}{b}(modp) ba(modp)的值,这个时候就需要用到费马小定理,怎么用呢?考虑: a ⋅ b − 1 ≡ x ( m o d p ) a\cdot b^{-1} \equiv x(modp) ab1x(modp)式中的 x x x就是我们要求的数,那么怎么求这个 x x x呢,考虑费马小定理,将两边同时乘上 b p − 1 b^{p-1} bp1,即 a ⋅ b p − 2 ≡ x ⋅ b p − 1 ( m o d p ) a\cdot b^{p-2}\equiv x\cdot b^{p-1}(mod p) abp2xbp1(modp)又根据费马小定理有 a p − 1 ≡ 1 ( m o d p ) a^{p-1}\equiv1(modp) ap11(modp),可以得出 a ⋅ b p − 2 ≡ x ( m o d p ) a\cdot b^{p-2} \equiv x(modp) abp2x(modp)
就得出答案了。
说了这么多,看到题吧。
https://nanti.jisuanke.com/t/A2017

这道题比较容易分析出答案为 2 n − 1 m o d p 2^{n-1}modp 2n1modp,这个证明直接递推下就有了。但让人蛋疼的是这个 n n n高达 1 0 100000 10^{100000} 10100000这么大。直接求肯定是不行的,那么这个时候就可以用费马小定理了,仔细分析你可以发现,答案其实就是 2 ( n ) m o d ( p − 1 ) m o d p ⋅ 2 p − 2 2^{(n)mod(p-1)}modp\cdot2^{p-2} 2(n)mod(p1)modp2p2, 那么就很明了,加上一个快速幂和同余就解决了

AC代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+5;
const ll mod=1e9+7;
string str;

ll poww(ll a,ll b){
	ll ans=1,base=a;
	while(b){
		if(b&1){
			ans*=base;
			ans%=mod;
		}
		b>>=1;
		base*=base;
		base%=mod;
	}
	return ans;
}


int main(){
	int t;
	scanf("%d",&t);
	while(t--){
		cin>>str;
		int n=str.length();
		ll ans=1,a=0;
		for(int i=0;i<n;i++){
			a=a*10+(str[i]-'0');
			a%=(mod-1);
		}
		ans=poww(2,a);
		ans=(ans*poww(2,mod-2))%mod;
		printf("%lld\n",ans);
	}
	return 0;
}

新的开始,每天都要快乐哈!
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值