结论:我数论太渣了……

言归正传……先列出几个常用的性质/结论

同余式:

1. da≡db (mod m) 则a≡b (mod m/(m,d) ) (这在取遍剩余系会用到)

2. a≡b (mod m)  m'|m , a≡b (mod m')

3. a≡b (mod mi) i=1..k 等价于 a≡b (mod M) M=[m1,m2,..mk]

一般剩余系:

剩余系就是可能余数组成的集合,简化剩余系也称既约剩余系,是模n的完全剩余系的一个子集,其中每个元素与n互素。

1. 模p的剩余系{rk},若(p,d)=1那么{d*rk}也是模p的剩余系

这个很重要,如果求ax mod p的既约剩余系的大小,我们只要利用同余式的性质1

转化为x*a/gcd(a,p) mod (p/gcd(a,p)),根据这个理论 x取值个数就是p/gcd(a,p)

2. 设模m1的既约剩余系为R1,m2的既约剩余系为R2,m1m2互质,则模m1m2的既约剩余系为R={x=m2x1+m1x2 (mod m1m2) | x1∈R1,x2∈R2}

这个结论证明可以考虑任意两个x互不同余即可(作差判断)

这就告诉我们一个很厉害的东西 S(M)表示M既约剩余系的大小的话,S(M)=S(m1)*S(m2)

3. 这个结论推广到k维就是,设模mk的既约剩余系为Rk, mk两两互质,M=∏mi 则模M的既约剩余系为R={ ∑M*mi-1*ai (mod M) | xi∈Ri }  

因此以后我们求模M的剩余系大小,可以对M质因数分解分别求出后再相乘

 

阶、原根、指标:

 阶(又叫指数):a,m为互素整数且m>=2 ,则使 ar≡1(mod m) 成立的最小正整数 r 记为 a 模 m 的指数,记作ord_m(a)

根据欧拉定理,显然ord_m(a)一定是φ(m)的约数

阶有几个性质: 1. ord_m(a)=xy 则 ord_m(ax)=y 2.ord_m(a)=x, ord_m(b)=y (x,y)=1 则ord_m(ab)=xy;

3. ord_m(a)=t ord_m(ax)=t/gcd(t,x) (其实就是性质1的变形)

原根:阶中要求(a,m)互素,所以a^x与m互素,所以ax模m的余数与m互素,这样这个余数只可能有 φ(m) 种不同的取值。

(这里我想到了了一个很有意思的结论:1~n内与n互质的数的和为{n*φ(n)+[n==1]} /2 

这里考虑gcd(i,n)=1,则gcd(n,n-i)=1,证明用反证法即可。)

当满足ord_m(a)=φ(m)的a称作模m的原根,记作g。

这有一个显然的结论若 x=0,1,2,3,...,φ(m)-1,则 gx 模 m 的余数都和 m 互素,并且模 m 两两不同余。

指标:简单来说,就是一切小于m且与m互质的数r,都存在唯一个数k(k<φ(m)),使得gk≡r (mod m)

我们就把k叫作r的指标,记作I(r)

这是一个非常有用的性质,之后的题目我们会经常看到他。

指标有这么几个性质:1. I(ab)≡I(a)+I(b) (mod m) 2. I(ak)≡kI(a) (mod m)

简而言之,指标就像是数论里的取对数。

原根和求指标将在后面的同余方程中起到巨大作用,但是首先我们要知道什么数有原根

直接上结论: 当且仅当m=2,4,pk,2pk时才有原根,p是某一奇素数

证明可以看《初等数论及其应用》

还有一个非常有用的定理是:若g是某一奇素数p的原根,那么g也是pk的原根,证明依然在《初等数论及其应用》

事实上,一个数p的原根的数目为φ(φ(p)) (考虑若g是p的原根,gu是p的原根当且仅当gcd(u,φ(p))=1)

另外我们注意到2的原根是1,4的原根是3,但其他2次幂是没有原根的(在高次剩余里,模2次幂会带来不小的麻烦)

事实上有一个恒等式:aφ(xy)/2≡1 (mod xy) (x,y互素且a与xy互素)

在2次幂的时候就有a^(2k)≡1 (mod 2k+2) 恒成立,所以2的3次及以上次幂没有原根

(补充一个很有意思的结论:5模2k+2的指数正好是2k

一个数的原根不止一个,一般就找最小的那个就可以了

其他的原根可用最小原根的gu表示(gu是p的原根当且仅当gcd(u,φ(p))=1)

找m的最小原根一般就是暴力枚举g,然后穷举m的每个质因数p,判断gφ(m)/p≡1 (mod m)是否成立(成立的话就不是原根)

一道找所有原根的题目

  1 #include<bits/stdc++.h>
  2 
  3 using namespace std;
  4 typedef long long ll;
  5 int phi[1000010],p[1000010],a[100010],ans[1000010],n,r,t;
  6 bool v[1000010];
  7 
  8 int gcd(int a,int b)
  9 {
 10     return (b==0)?a:gcd(b,a%b);
 11 }
 12 
 13 ll quick(ll x,int y,int mo)
 14 {
 15     ll s=1;
 16     while (y)
 17     {
 18         if (y&1) s=s*x%mo;
 19         x=x*x%mo;
 20         y>>=1;
 21     }
 22     return s;
 23 }
 24 
 25 int check(int n)
 26 {
 27     if (n%2==0) return -1;
 28     if (!v[n]) return n;
 29     for (int i=2; p[i]*p[i]<=n; i++)
 30         if (n%p[i]==0)
 31         {
 32             while (n%p[i]==0) n/=p[i];
 33             if (n>1) return -1;
 34             else return p[i];
 35         }
 36     return -1;
 37 }
 38 
 39 bool work(int g,int mo)
 40 {
 41     if (gcd(g,mo)!=1) return 0;
 42     for (int i=1; i<=r; i++)
 43         if (quick(g,phi[mo]/a[i],mo)==1) return 0;
 44     return 1;
 45 }
 46 
 47 int getg(int mo)
 48 {
 49     int n=phi[mo];
 50     r=0;
 51     for (int i=1; p[i]*p[i]<=n; i++)
 52         if (n%p[i]==0)
 53         {
 54             while (n%p[i]==0) n/=p[i];
 55             a[++r]=p[i];
 56         }
 57     if (n>1) a[++r]=n;
 58     for (int i=2; i<mo; i++)
 59         if (work(i,mo)) return i;
 60 }
 61 
 62 int main()
 63 {
 64     phi[1]=1;
 65     for (int i=2; i<=1000000; i++)
 66     {
 67         if (!v[i])
 68         {
 69             phi[i]=i-1;
 70             p[++t]=i;
 71         }
 72         for (int j=1; j<=t; j++)
 73         {
 74             if (i*p[j]>1000000) break;
 75             v[i*p[j]]=1;
 76             if (i%p[j]==0)
 77             {
 78                 phi[i*p[j]]=phi[i]*p[j];
 79                 break;
 80             }
 81             else phi[i*p[j]]=phi[i]*(p[j]-1);
 82         }
 83     }
 84     while (scanf("%d",&n)!=EOF)
 85     {
 86         if (n==2)
 87         {
 88             puts("1");
 89             continue;
 90         }
 91         if (n==4)
 92         {
 93             puts("3");
 94             continue;
 95         }
 96         int ch=(n%2==1)?check(n):check(n/2);
 97         if (ch==-1)
 98         {
 99             puts("-1");
100             continue;
101         }
102         int g=getg(n);
103         int l=0;
104         for (int i=1; i<=phi[n]; i++)
105             if (gcd(i,phi[n])==1) ans[++l]=quick(g,i,n);
106         sort(ans+1,ans+1+l);
107         for (int i=1; i<=l; i++)
108         {
109             printf("%d",ans[i]);
110             if (i==l) puts(""); else printf(" ");
111         }
112     }
113 }
hdu4992

相关文章: