题目描述
求关于 x 的同余方程 ax ≡ 1 (mod b)的最小正整数解。
输入输出格式
输入格式:
输入只有一行,包含两个正整数 a, b,用一个空格隔开。
输出格式:
输出只有一行,包含一个正整数 x0,即最小正整数解。输入数据保证一定有解。
输入输出样例
输入样例#1:
3 10
输出样例#1:
7
说明
【数据范围】
对于 40%的数据,2 ≤b≤ 1,000;
对于 60%的数据,2 ≤b≤ 50,000,000;
对于 100%的数据,2 ≤a, b≤ 2,000,000,000。
NOIP 2012 提高组 第二天 第一题
//智商太低,搞这个搞了一晚上……
解题思路
我太菜了,不会扩欧,用的是dalao教的费马小定理,但这题没规定b一定是质数,所以要用欧拉定理,费马小定理其实就是欧拉定理的特殊情况。
1、同余的传递性。
若$$a equiv bmod p $$ 且$$c equiv bmod p $$ 则$$ a equiv cmod p$$
2、欧拉定理(同余的那个)$$a^{phi(b)} equiv 1mod b$$
3、题目要求的那个式子$$ax equiv 1mod b$$
以上三项代换一下得到$ax equiv a^{phi(b)} mod{b}$,我不知道为什么左边的a可以除过去——$x equiv a^{phi(b)-1}mod b$,于是最小的x就是$a^{phi(b)-1}mbox{%} b$。
源代码
#include<stdio.h> #include<time.h> #include<math.h> #include<algorithm> #include<cstring> #define ll long long long long phi(long long n) { ll res=n,now=n,max=ceil(sqrt(n)); int b[max+1],size=0;ll prime[max/2]; memset(b,1,sizeof(b));b[1]=0; for(int i=2;i<=max;i++){//不筛素数表会TLE一个点,本机要跑44s…… if(b[i]==0) continue; size++;prime[size]=i; for(int t=2*i;t<=max;t+=i) b[t]=0; } for(int i=1;i<=size;i++){ if(now%prime[i]==0){ res=res/prime[i]*(prime[i]-1); while(now%prime[i]==0){ now/=prime[i]; } } if(now==1) break; } if(now!=1) res=res/now*(now-1); return res; } long long p(long long n,long long k,long long mo) { if(k==0) return 1; if(k==1) return n%mo; long long a=p(n,k>>1,mo)%mo; a=a*a%mo; //printf("%lld %lld ",k,a); return a*p(n,k&1,mo)%mo; } int main() { //freopen("mod.in","r",stdin); //freopen("mod.out","w",stdout);//cogs的印记…… long long a,b; //double start=clock(); scanf("%lld%lld",&a,&b); long long k=phi(b)-1; //printf("%lf ",(clock()-start)/1000000); printf("%lld ",(p(a,k,b)+b)%b); return 0; }