一.基本理论

1.基本概念:

给定一个正整数p,任意一个整数n,一定存在等式 n = k p + r n = kp + r n=kp+r
  
其中 k r k、r kr是整数,且 0 r < p 0 ≤ r < p 0r<p,称呼 k k k n n n除以 p p p的商, r r r n n n除以p的余数。

对于正整数p和整数 a , b a,b a,b,定义如下运算:

取模运算: a % p a m o d p a \% p(或a mod p) a%pamodp,表示a除以p的余数。

模p加法: ( a + b ) % p (a + b) \% p (a+b)%p ,其结果是 a + b a+b a+b算术和除以p的余数,也就是说, ( a + b ) = k p + r (a+b) = kp +r, (a+b)=kp+r ( a + b ) % p = r (a + b) \% p = r。 (a+b)%p=r

模p减法: ( a b ) % p (a-b) \% p (ab)%p,其结果是 a b a-b ab算术差除以p的余数。

模p乘法: ( a b ) % p (a * b) \% p (ab)%p,其结果是 a b a*b ab算术乘法除以p的余数。

2.说明:

1. 同余式:正整数 a b a,b ab 分别对 p p p 取模,它们的余数相同,记做 a b % p a ≡ b \% p ab%p或者 a b ( m o d p ) a ≡ b (mod p)。 ab(modp)

2. n % p n \% p n%p得到结果的正负由被除数n决定,与p无关。例如: 7 % 4 = 3 7\%4 = 3 7%4=3 7 % 4 = 3 7 % 4 = 3 7 % 4 = 3 -7\%4 = -3, 7\%-4 = 3, -7\%-4 = -3 7%4=37%4=37%4=3

3.基本性质

(1)若 p ( a b ) p|(a-b), p(ab) a b ( % p ) a≡b (\% p) ab(%p)。例如 11 4 ( % 7 ) 11 ≡ 4 (\% 7), 114(%7) 18 4 ( % 7 ) 18 ≡ 4(\% 7) 184(%7)

(2) ( a % p ) = ( b % p ) (a \% p)=(b \% p) (a%p)=(b%p)意味 a b ( % p ) a≡b (\% p) ab(%p)

(3)对称性: a b ( % p ) a≡b (\% p) ab(%p)等价于 b a ( % p ) b≡a (\% p) ba(%p)

(4)传递性:若 a b ( % p ) a≡b (\% p) ab(%p) b c ( % p ) b≡c (\% p) bc(%p),则 a c ( % p ) a≡c (\% p) ac(%p)

运算规则

模运算与基本四则运算有些相似,但是除法例外。其规则如下:

( a + b ) % p = ( a % p + b % p ) % p (a + b) \% p = (a \% p + b \% p) \% p (a+b)%p=(a%p+b%p)%p (1)

( a b ) % p = ( a % p b % p ) % p (a - b) \% p = (a \% p - b \% p) \% p (ab)%p=(a%pb%p)%p (2)

( a b ) % p = ( a % p b % p ) % p (a * b) \% p = (a \% p * b \% p) \% p (ab)%p=(a%pb%p)%p (3)

( a b ) % p = ( ( a % p ) b ) % p (a^b) \% p = ((a \% p)^b) \% p (ab)%p=((a%p)b)%p (4)

结合率: ( ( a + b ) % p + c ) % p = ( a + ( b + c ) % p ) % p ((a+b) \% p + c) \% p = (a + (b+c) \% p) \% p ((a+b)%p+c)%p=(a+(b+c)%p)%p(5)

( ( a b ) % p c ) % p = ( a ( b c ) % p ) % p ((a*b) \% p * c)\% p = (a * (b*c) \% p) \% p ((ab)%pc)%p=(a(bc)%p)%p (6)

交换率: ( a + b ) % p = ( b + a ) % p (a + b) \% p = (b+a) \% p (a+b)%p=(b+a)%p (7)

( a b ) % p = ( b a ) % p (a * b) \% p = (b * a) \% p (ab)%p=(ba)%p (8)

分配率: ( ( a + b ) % p c ) % p = ( ( a c ) % p + ( b c ) % p ) % p ((a +b)\% p * c) \% p = ((a * c) \% p + (b * c) \% p) \% p ((a+b)%pc)%p=((ac)%p+(bc)%p)%p (9)

**重要定理:**若 a b ( % p ) a≡b (\% p), ab(%p)则对于任意的 c c c,都有 ( a + c ) ( b + c ) ( % p ) (a + c) ≡ (b + c) (\%p) (a+c)(b+c)(%p);(10)

a b ( % p ) a≡b (\% p) ab(%p),则对于任意的 c c c,都有 ( a c ) ( b c ) ( % p ) (a * c) ≡ (b * c) (\%p) (ac)(bc)(%p);(11)

a b ( % p ) a≡b (\% p) ab(%p) c d ( % p ) c≡d (\% p) cd(%p),则 ( a + c ) ( b + d ) ( % p ) (a + c) ≡ (b + d) (\%p) (a+c)(b+d)(%p) ( a c ) ( b d ) ( (a - c) ≡ (b - d) (%p) (ac)(bd)(

( a c ) ( b d ) ( % p ) (a * c) ≡ (b * d) (\%p) (ac)(bd)(%p) ( a / c ) ( b / d ) ( % p ) (a / c) ≡ (b / d) (\%p) (a/c)(b/d)(%p); (12)

a b ( % p ) a≡b (\% p) ab(%p),则对于任意的 c c c,都有 a c b c ( % p ) ac≡ bc (\%p) acbc(%p); (13)

二.基本应用

1.判别奇偶数  2.判别素数3. 最大公约数  4.模幂运算

1.快速幂运算

UVA10006 Carmichael Numbers

一个数是 C a r m i c h a e l N u m b e r s Carmichael Numbers CarmichaelNumbers
得满足它不是质数并且对于每一个 i ( 1 < i < n ) i (1 < i < n) i(1<i<n)都满足 i n i m o d    n i ^ n \equiv i \mod n inimodn
我们如果暴力求解 i n i ^ n in
时间复杂度是 O ( n ) O(n) O(n)妥妥的 T L E TLE TLE
我们引进一个高效求 x y x ^ y xy 的东西:
快速幂
什么是快速幂呢,就是把 x y x ^ y xy
变为
(1) y m o d    2 = 0 : x y = ( x 2 ) y / 2 y \mod 2 = 0 : x ^ y = (x ^ 2) ^ {y / 2} ymod2=0:xy=(x2)y/2(

(2) y m o d    2 = 1 : x y = x x y 1 y \mod 2 = 1 : x ^ y = x * x ^ {y - 1} ymod2=1:xy=xxy1 ,此时y为偶数

因为每次 y y y 都会除以2
所以快速幂的时间复杂度就为 O ( l o g 2 y ) O(log_2y) O(log2y)
那么此题的时间复杂度就为 O ( T ( n + n l o g 2 n ) ) O(T * (\sqrt{n} + n * log_2n)) O(T(n +nlog2n))

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ifstream in("input.txt");
ofstream out("output.txt");
#define debug(x) cout<<"# "<<x<<endl
const ll N=100005;
const ll base=137;
const ll mod=2147483647;
const ll INF=1<<30;
ll n,m,x;
ll mod_pos(ll x,ll n,ll mod)
{
    ll res=1;
    while(n)
    {
        if(n&1)res=res*x%mod;
        x=x*x%mod;
        n>>=1;
    }
    return res;
}
int main()
{
    while(~scanf("%lld",&n)&&n!=0)
    {
        bool flag=true;
        for(int i=2;i*i<=n;++i){
            if(n%i==0)
                flag=false;
        }
        if(flag){
            printf("%lld is normal.\n",n);
            continue;
        }
        flag=true;
        for(int i=2;i<n;++i)
        {
            if(mod_pos(i,n,n)!=i){
                flag=false;
                printf("%lld is normal.\n",n);
                break;
            }
        }
        if(flag)printf("The number %lld is a Carmichael number.\n",n);
    }
    return 0;
}