51nod 1038(n次剩余)
来源:互联网 发布:淘宝坑产是什么意思 编辑:程序博客网 时间:2024/06/06 05:56
题目链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1038;
题目分析:
1、原根:原根的分布比较广,最小原根通常也较小,可以枚举正整数来快速找原根,对于一个代检查的p,对p-1的每一个素因子a,检查,若成立则说明g不是原根。
2、离散对数 :给定的x,n,m 求的解(其中m是素数)。令s=,则有,即有。将所有的放入有序表中,从小到大枚举b,得到。
把看曾未知数解模线性方程。若解能在有序表中找到,则停止枚举,此时。
3:N次剩余:给定N,a,p,求出在模p意义下的所有解(其中p是素数)。
令g为p的原根,因为p为素数,则,所以找到原根g就可以将{1,2,…,p-1}的数与{}建立一一对应关系。
则,则有:
因为p是素数,所以方程左右都不可以为0。这样就可以将这p-1个取值与指数建立对应关系。原问题转换为:
对于y解模线性方程就可以解决。而则可以用解离散对数的方法求出。
代码如下:
#include <map>#include <math.h>#include <vector>#include <stdio.h>#include <string.h>#include <iostream>#include <algorithm>#include <functional>using namespace std;long long quick_mod(long long a,long long b,long long mod){ long long ans=1; while(b){ if(b&1)ans=ans*a%mod; b>>=1; a=a*a%mod; } return ans;}//快速幂long long ex_gcd(long long a, long long b, long long &x, long long &y) { if (b == 0) { x = 1, y = 0; return a; } else { long long r = ex_gcd(b, a % b, y, x); y -= x * (a / b); return r; }}//扩展欧几里得算法vector<long long>a;bool g_text(long long g,long long p){ for(long long i=0;i<a.size();i++) if(quick_mod(g,(p-1)/a[i],p)==1) return 0; return 1;}long long primitive_root(long long p){ long long tmp=p-1; for(long long i=2;i<=tmp/i;i++){ if(tmp%i==0){ a.push_back(i); while(tmp%i==0)tmp/=i; } } if(tmp!=1)a.push_back(tmp); long long g=1; while(true){ if(g_text(g,p)) return g; ++g; }}//求解原根struct sa{ long long x; int id; bool operator<(const sa &b)const{ if (x == b.x) return id < b.id; return x<b.x; }}rec[100500];//用rec存离散对数long long discerte_log(long long x,long long n,long long m){ int s=(int)(sqrt((double)m+0.5)); while((long long)s*s<=m)s++; long long cur=1; sa tmp; for(int i=0;i<s;i++){ tmp.x=cur,tmp.id=i; rec[i]=tmp; cur=cur*x%m; } sort(rec,rec+s); //这里不能用map查找比较慢,采用排序二分就快了 long long mul= quick_mod(cur, m - 2, m) % m; //这里有的方法是在下面的循环里求解快速幂,但本题是不行的 要在循环外面弄,保证时间 cur=1; for(long long i=0;i<s;i++){ long long more=n*cur%m; tmp.x=more,tmp.id=-1; int j=lower_bound(rec,rec+s,tmp)-rec; if(rec[j].x==more){ return i*s+rec[j].id; } cur=cur*mul%m; } return -1;}//求解离散对数vector<long long>residue(long long p,long long n,long long a){ vector<long long>ret; if(a==0){ ret.push_back(0); return ret; } long long g=primitive_root(p); long long m=discerte_log(g,a,p); if(m==-1)return ret; long long A=n,B=p-1,C=m,x,y; long long G=ex_gcd(A,B,x,y); if(C%G!=0)return ret; x=x*(C/G)%B; long long delta=B/G; for(int i=0;i<G;i++){ x=((x+delta)%B+B)%B; ret.push_back(quick_mod(g,x,p)); } sort(ret.begin(),ret.end()); ret.erase(unique(ret.begin(),ret.end()),ret.end()); return ret;}//求解n次剩余int main(){ int t; scanf("%d",&t); while(t--){ long long p,A,b; a.clear(); scanf("%I64d%I64d%I64d",&p,&A,&b); vector<long long>ans; ans=residue(p,A,b); if(ans.empty()){ puts("No Solution"); } else { for(unsigned int i=0;i<ans.size();i++){ printf("%I64d ",ans[i]); } puts(""); } } return 0;}
0 0
- 51nod 1038(n次剩余)
- N次剩余 (hdu 3930)
- hdu 3930 N次剩余
- SGU 261. Discrete Roots (N次剩余)
- SGU 261 Discrete Roots N次剩余
- N次剩余(详解+例题+代码)
- 51nod 中国剩余定理
- 51nod--中国剩余定理
- 51 nod 中国剩余定理
- sgu——261(数论之N次剩余问题)
- 51nod1079---中国剩余定理(51nod基础:数论)
- 51nod 1079 中国剩余定理 (模板)
- 51Nod-中国剩余定理(加优化版)
- 51Nod-集合计数(拓展欧几里得+中国剩余定理)
- 51nod:1079 中国剩余定理(数学)
- 51Nod 1079中国剩余定理(孙子定理)
- HDU 3223 Decrypt Messages 【N次剩余+模拟】
- 51nod 1079 中国剩余定理
- MAC 下vim 配置(Linux通用)
- C/C++基本数据类型所占字节数
- TCP/IP、Http、Socket的区别
- Java中一中读入字符的方法
- Servlet 数据库访问
- 51nod 1038(n次剩余)
- ubuntu 14.04修改root环境变量
- 软工文档总结篇(一)
- 第2.1.9章 WEB系统最佳实践Spring文件配置之spring-dubbo.xml
- c#中字符串操作函数
- 判断完全二叉树
- 块级元素与内联元素
- 关于重载和比较函数
- 关于C语言内存移动函数的写法详解