二次剩余与n次剩余

二次剩余求的是这个东西

如果给定x,再给定若干个大的质数p,如果结果a相同,那么x是完全平方数?

给出别人的二次剩余的代码:

 1 /*poj 1808
 2   题意:
 3   判断平方剩余,即判断(x^2)%p=a是否有解。
 4   限制:
 5   |a| <= 1e9 && a % p !=0; 2 < p < 1e9 && p为奇素数。
 6   思路:
 7   用欧拉准则计算勒让德符号(用来判断平方剩余)
 8  */
 9 #include<iostream>
10 #include<cstdio>
11 using namespace std;
12 #define LL __int64
13 LL a_b_MOD_c(LL a,LL b,LL mod){
14     LL ret = 1;
15     a %= mod;
16     while(b){
17         if(b & 1) ret = ret * a % mod;
18         a = a * a % mod;
19         b >>= 1;
20     }
21     return ret;
22 }
23 //(x^2)%n=a 求平方剩余,n必须是奇素数
24 //注意:如果a为负,则看题意,是否要化为a=(a%n+n)%n
25 int modsqr(int a,int n){
26     int b,k,i,x;
27     if(n==2) return a%n;
28     if(a_b_MOD_c(a,(n-1)/2,n)==1){
29         if(n%4==3)
30             x=a_b_MOD_c(a,(n+1)/4,n);
31         else{
32             for(b=1;a_b_MOD_c(b,(n-1)/2,n)==1;b++){
33                 i=(n-1)/2;
34                 k=0;
35             }
36             do{
37                 i/=2;
38                 k/=2;
39                 if((a_b_MOD_c(a,i,n)*a_b_MOD_c(b,k,n)+1)%n==0)
40                     k+=(n-1)/2;
41             }
42             while(i%2==0);
43             x=(a_b_MOD_c(a,(i+1)/2,n)*a_b_MOD_c(b,k/2,n))%n;
44         }
45         if(x*2>n)
46             x=n-x;
47         return x;
48     }
49     return -1;
50 }
51 //用欧拉准则计算勒让德符号(用来判断平方剩余)
52 //表示为(a|p) a为整数,p为奇素数(所以m=2不适用勒让德符号),有三种情况。
53 //1. (a|p)=0, if(a%p==0)
54 //2. (a|p)=1, if(a%p!=0 && (x^2)%p=a 有整数解)
55 //3. (a|p)=-1,if((x^2)%p=a 无整数解)
56 //注意:如果a为负,则看题意,是否要化为a=(a%p+p)%p
57 int lrd(LL a,LL p){
58     LL ret=a_b_MOD_c(a,(p-1)>>1,p);
59     if(ret==1)
60         return 1;
61     return -1;
62 }
63 int main(){
64     int T,cas=0;
65     int a,n;
66     scanf("%d",&T);
67     while(T--){
68         scanf("%d%d",&a,&n);
69         a=(a+n)%n;    //以后注意给出余数的时候,要注意它是不是负的
70         
71         //求平方剩余
72         //cout<<modsqr(a,n)<<endl;
73         printf("Scenario #%d:\n%d\n\n",++cas,lrd(a,n));
74     }
75     return 0;
76 }

然后是n次剩余

  1 /*hdu 3930
  2   题意:
  3   给定newx, k, m, 方程 (x^k)%m=newx, 求在模m意义下的所有解x。
  4   限制:
  5   0 <= newx, m, k <= 1.5*10^15; m是素数。
  6   思路:
  7   N次剩余
  8  */
  9 #include <iostream>
 10 #include <cstdio>
 11 #include <cmath>
 12 #include <cstring>
 13 #include <vector>
 14 #include <algorithm>
 15 using namespace std;
 16 #define LL __int64
 17 #define PB push_back
 18 LL mul(LL a,LL b,LL m){
 19     LL ret = 0;
 20     a %= m;
 21     while(b){
 22         if(b & 1) ret = (ret + a) % m;
 23         a = (a + a) % m;
 24         b >>= 1;
 25     }
 26     return ret;
 27 }
 28 LL a_b_MOD_c(LL a,LL b,LL m){
 29     LL ret = 1;
 30     a %= m;
 31     while(b){
 32         if(b&1) ret = mul(ret,a,m);
 33         a = mul(a,a,m);
 34         b >>= 1;
 35     }
 36     return ret;
 37 }
 38  
 39 LL ext_gcd(LL a,LL b,LL &x,LL &y){
 40     if(b==0) { x=1, y=0; return a; }
 41     LL ret= ext_gcd(b,a%b,y,x);
 42     y-= a/b*x;
 43     return ret;
 44 }
 45 vector<LL> a;
 46 bool g_test(LL g,LL p){
 47     for(LL i=0;i<a.size();++i)
 48         if(a_b_MOD_c(g,(p-1)/a[i],p)==1)
 49             return 0;
 50     return 1;
 51 }
 52 LL pri_root(LL p){
 53     a.clear();
 54     LL tmp=p-1;
 55     for(LL i=2;i<=tmp/i;++i)
 56         if(tmp%i==0){
 57             a.push_back(i);
 58             while(tmp%i==0)
 59                 tmp/=i;
 60         }
 61     if(tmp!=1)
 62         a.push_back(tmp);
 63     LL g=1;
 64     while(true){
 65         if(g_test(g,p))
 66             return g;
 67         ++g;
 68     }
 69 }
 70 const int HASH_MOD=9876543;
 71 LL key[HASH_MOD], val[HASH_MOD];
 72 int head[HASH_MOD], next[HASH_MOD];
 73 struct Hash{
 74     int tot;
 75     void init(){
 76         memset(head, -1, sizeof(head));
 77         tot = 0;
 78     }
 79     LL insert(LL x, LL y){
 80         int k = x % HASH_MOD;
 81         key[tot] = x;
 82         val[tot] = y;
 83         next[tot] = head[k];
 84         head[k] = tot++;
 85     }
 86     LL find(LL x){
 87         int k = x % HASH_MOD;
 88         for(int i = head[k]; i != -1; i = next[i])
 89             if(key[i] == x)
 90                 return val[i];
 91         return -1;
 92     }
 93 }hs;
 94 //求解模方程a^x=b(mod m),n为素数,无解返回-1  
 95 //注意:要求0 < a < m; 0 <= b < m; 否则按题意自己转化。
 96 //复杂度O(sqrt(m))
 97 LL log_mod(LL a, LL b, LL m){
 98     hs.init();
 99     LL s = ceil(sqrt(m + 0.5));
100     LL cur = 1;
101     for (int i = 0; i < s; ++i){
102         if(hs.find(cur)==-1) hs.insert(cur,i);    //记得先判重,在插入
103         cur = cur * a % m;
104     }
105  
106     LL v = a_b_MOD_c(a, (m - s - 1 + m) % m, m);
107     for(int i = 0; i < s; ++i){
108         LL tmp = hs.find(b);
109         if(tmp!=-1)
110             return s * i + tmp;
111         b=b*v%m;
112     }
113     return -1;
114 }
115 /*n次剩余
116   任务:
117   给定N, a, p, 求出(x^N)%p=a 在模p意义下的所有解x。
118   说明:
119   令g为p的原根,因为p为素数,所以phi(p)=p-1。
120   由原根的性质得:
121   如果g为p的原根,则:g^i mod p != g^j mod p (p为素数), 其中i != j且i, j介於1至(p-1)之间
122   所以,可以设g^y=x, g^t=a,则有:
123   g^(y*N)%p=g^t
124   又由原根的性质:
125   g^(y*N)%p=g^t -> (y*N)%(p-1)=t (此方程可以由拓展欧几里得解)
126   另外g^t=a可以由离散对数求出
127  */
128 vector<LL> residue(LL p, LL N, LL a){
129     LL g = pri_root(p);
130     g %= p;
131     LL m = log_mod(g, a, p);
132     vector<LL> ret;
133     if(a == 0){
134         ret.PB(0);
135         return ret;
136     }
137     if(m == -1)
138         return ret;
139     LL A = N, B = p - 1, C = m, x, y;
140     LL d = ext_gcd(A, B, x, y);
141     if(C % d != 0) return ret;
142     x = x * (C / d) % B;
143     LL delta = B / d;
144     for(int i = 0; i < d; ++i){
145         x = ((x + delta) % B + B) % B;
146         ret.PB(a_b_MOD_c(g, x, p));
147     }
148     sort(ret.begin(), ret.end());
149     ret.erase(unique(ret.begin(), ret.end()), ret.end());
150     return ret;
151 }
152 int main(){
153     int cas = 0;
154     LL k,m,newx;
155     while(scanf("%I64d%I64d%I64d",&k, &m, &newx)!=EOF){
156         vector<LL> ans;
157         ans = residue(m,k,newx);
158         printf("case%d:\n",++cas);
159         if(ans.size()==0) puts("-1");
160         for(int i = 0; i < ans.size(); ++i)
161             printf("%I64d\n",ans[i]);
162     }
163     return 0;
164 }

猜你喜欢

转载自www.cnblogs.com/aininot260/p/9709283.html