URAL 1132 二次剩余
2015-11-12 20:12
337 查看
URAL 1132
题目链接:
http://acm.timus.ru/problem.aspx?space=1&num=1132
题意:
对于方程x * x = n (mod p)是否有解,p是素数且与n互素
思路:
二次剩余版题。
感谢ACdreamer大神http://blog.csdn.net/acdreamers/article/details/10182281
关于二次剩余:
概念:x * x = n(mod p),存在解时,x为n关于p的二次剩余(p是奇素数)
相关定理:
1)n ^ ((p - 1) / 2) = +-1mod(p)
a)费马小定理知,然后用完全平方差因式分解
2)方程有解当且仅当n ^ (p-1) / 2 = 1mod(p)
a)
3)对于a >= 0 && a < p,若w = a * a - n满足w关于p没有二次剩余,则(a+sqrt(w))^((1+p)/2)为方程的一个解。
4)方程至多两个解,且满足x1 + x2 = p.
算法步骤:
1)判断x * x = n (mod p)是否有解
2)枚举a求出合法的w
3)(难理解的地方)由于方程(a+sqrt(w))^((1+p)/2)出现根号,所以要用类似复数乘法的二元域计算乘法,详见代码。
4)二元域的第一项为解,求出另一个解。
本题有坑点就是a不一定小于n,所以a>n时直接特判n==2 && a==1会WA。
源码:
乱版:
精简版:
题目链接:
http://acm.timus.ru/problem.aspx?space=1&num=1132
题意:
对于方程x * x = n (mod p)是否有解,p是素数且与n互素
思路:
二次剩余版题。
感谢ACdreamer大神http://blog.csdn.net/acdreamers/article/details/10182281
关于二次剩余:
概念:x * x = n(mod p),存在解时,x为n关于p的二次剩余(p是奇素数)
相关定理:
1)n ^ ((p - 1) / 2) = +-1mod(p)
a)费马小定理知,然后用完全平方差因式分解
2)方程有解当且仅当n ^ (p-1) / 2 = 1mod(p)
a)
3)对于a >= 0 && a < p,若w = a * a - n满足w关于p没有二次剩余,则(a+sqrt(w))^((1+p)/2)为方程的一个解。
4)方程至多两个解,且满足x1 + x2 = p.
算法步骤:
1)判断x * x = n (mod p)是否有解
2)枚举a求出合法的w
3)(难理解的地方)由于方程(a+sqrt(w))^((1+p)/2)出现根号,所以要用类似复数乘法的二元域计算乘法,详见代码。
4)二元域的第一项为解,求出另一个解。
本题有坑点就是a不一定小于n,所以a>n时直接特判n==2 && a==1会WA。
源码:
乱版:
#include <cstdio> #include <cmath> #include <cstring> #include <cstdlib> #include <algorithm> #include <iostream> #include <string> using namespace std; #define LL long long struct Twice { LL t1, t2; LL i, mod; Twice(){t1 = t2 = i = 0;} Twice(LL _t1, LL _t2, LL _t3, LL p){t1 = _t1, t2 = _t2, i = _t3, mod = p;} Twice operator * (Twice a)const{ Twice ans; ans.t1 = (t1 * a.t1 % a.mod + t2 * a.t2 % a.mod * a.i) % a.mod; ans.t2 = (t1 * a.t2 % a.mod + t2 * a.t1 % a.mod) % a.mod; ans.i = i; ans.mod = mod; return ans; } }; Twice power(Twice a, LL x, LL p) { Twice ans = Twice(1, 0, a.i, p); while(x){ if(x & 1) ans = (ans * a); a = (a * a); x >>= 1; } return ans; } LL ppow(LL a, LL x, LL p) { LL res = 1; while(x){ if(x & 1) res = (res * a) % p; a = (a * a) % p; x >>= 1; } return res; } LL Legendre(LL a, LL p) { return ppow(a, (p - 1) >> 1, p); } LL solve(LL a, LL p) { if(p == 2) return 1; if(Legendre(a, p) + 1 == p) return -1; LL t1, t2; for(LL i = 0 ; i < p ; i++){ LL temp = i * i - a; temp = (temp % p + p) % p; if(Legendre(temp, p) + 1 == p){ t1 = i, t2 = temp; break; } } // printf("t1 = %I64d, t2 = %I64d\n", t1, t2); Twice u = Twice(t1, 1, t2, p); u = power(u, (p + 1) / 2, p); return u.t1; } int main() { int T; LL a, n; scanf("%d", &T); while(T--){ cin >> a >> n; a %= n; // scanf("%lld%lld", &a, &n); LL res = solve(a, n); if(n == 2){ if(a == 1) printf("1\n"); continue; } if(res == -1){ printf("No root\n"); continue; } // printf("res = %I64d\n", res); LL b = n - res; if(res > b) swap(res, b); if(res != b) cout << res << " " << b << endl; else cout << res << endl; } return 0; }
精简版:
#include <cstdio> #include <cstring> #include <cmath> #include <cstdlib> #include <algorithm> #include <iostream> #include <string> using namespace std; #define LL long long LL n, p; LL a, w; struct Twice { LL a, b; Twice(){} Twice(LL _a, LL _b){a = _a, b = _b;} Twice operator * (Twice rbs)const{ Twice ans; ans.a = (a * rbs.a + b * rbs.b * w) % p; ans.b = (b * rbs.a + a * rbs.b) % p; return ans; } }; LL ppow(LL a, LL x) { LL res = 1; while(x){ if(x & 1) res = (res * a) % p; a = (a * a) % p; x >>= 1; } return res; } Twice ppow(Twice a, LL x) { Twice res = Twice(1, 0); while(x){ if(x & 1) res = (res * a); a = (a * a); x >>= 1; } return res; } LL Legendre(LL a, LL x) { return ppow(a, (x - 1) / 2); } LL solve(LL n, LL p) { if(Legendre(n, p) + 1 == p) return -1; for(a = 0 ; a < p ; a++){ w = a * a - n; w = (w % p + p) % p; if(Legendre(w, p) + 1 == p) break; } Twice ans = ppow(Twice(a, 1), (p + 1) / 2); return ans.a; } int main() { int T; scanf("%d", &T); while(T--){ scanf("%I64d%I64d", &n, &p); // printf("n = %I64d, p = %I64d\n", n, p); if(p == 2){ printf("1\n"); continue; } LL a = solve(n, p); if(a == -1){ printf("No root\n"); continue; } LL b = p - a; if(a > b) swap(a, b); printf("%I64d %I64d\n", a, b); } return 0; }
相关文章推荐
- 黑马程序员——正则表达式
- C语言格式化输入输出
- Locale(编码问题)
- 关于input的file框onchange事件触发一次失效的新的解决方法
- 字符串指定位置插入
- PostgreSQL安装的问题
- Git的认知及基础操作
- 2015-2016 ACM-ICPC, NEERC, Moscow Subregional Contest K. King’s Rout(拓扑排序)
- MarkDown页内跳转实现
- HDU-5532(LIS-nlogn)
- Android Studio开发环境搭建准备
- AsyncTask和Handler对比
- web前端 常用meta标签
- C# 多线程学习系列三:线程优先级、线程同步以及向线程传递参数
- Android 应用签名
- poj 2531 Network Saboteur(经典dfs)
- java jni 入门7 - 访问数组元素
- 字符搜索
- 延迟加载
- 欢迎使用CSDN-markdown编辑器