二次剩余求的是这个东西
如果给定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: %d ",++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: ",++cas); 159 if(ans.size()==0) puts("-1"); 160 for(int i = 0; i < ans.size(); ++i) 161 printf("%I64d ",ans[i]); 162 } 163 return 0; 164 }