首页 > 代码库 > 洛谷 P1082 同余方程

洛谷 P1082 同余方程

题目描述

求关于 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 b\mod p $$    且$$b \equiv c\mod p $$    则$$ a \equiv c\mod p$$

    2、欧拉定理(同余的那个)$$a^{\phi(b)} \equiv 1\mod b$$

    3、题目要求的那个式子$$ax \equiv 1\mod 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 longlong 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\n",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\n",(clock()-start)/1000000);    printf("%lld\n",(p(a,k,b)+b)%b);    return 0;}

 

洛谷 P1082 同余方程