x^a=b(mod c)求解x在[0,c-1]上解的个数模板+原根求法
/*************************************
求解x^a=b(mod c) x在[0,c-1]上解的个数模板
输入:1e9>=a,b>=1,1e9>=c>=3.
返回:调用xaeqbmodc(a,b,c),返回解的个数
复杂度: 找原根的复杂度很低,所以总的复杂度为O(c^0.5)
************************************/ typedef long long ll;
#define HASH_N 100007 struct hashnode
{
int next;
ll key;
int j;
}HashLink[ HASH_N ]; int hashpre[ HASH_N ],hashcnt; void hash_insert(ll x,ll key,int j)
{
for(int p=hashpre[x];p!=-;p=HashLink[p].next)
{
if(HashLink[p].key==key) return ;
}
HashLink[ hashcnt ].key = key;
HashLink[ hashcnt ].j = j;
HashLink[ hashcnt ].next = hashpre[x];
hashpre[x] = hashcnt++;
} int hash_get(ll key)
{
ll x=key%HASH_N;
for(int p=hashpre[x];p!=-;p=HashLink[p].next)
{
if( HashLink[p].key == key ) return HashLink[p].j;
}
return -;
} ll gcd(ll a,ll b)
{
if(b==) return a;
return gcd(b,a%b);
} //ax + by = gcd(a,b)
//传入固定值a,b.放回 d=gcd(a,b), x , y
void extendgcd(long long a,long long b,long long &d,long long &x,long long &y)
{
if(b==){d=a;x=;y=;return;}
extendgcd(b,a%b,d,y,x);
y-=x*(a/b);
} //Ax=1(mod M)
//返回x的范围是[0,M-1]
ll GetNi(ll A,ll M)
{
ll rex=,rey=;
ll td=;
extendgcd(A,M,td,rex,rey);
return (rex%M+M)%M;
} //a^b%mod 快速幂
long long Quk_Mul(long long a,long long b,long long mod)
{
long long qsum=;
while(b)
{
if(b&) qsum=(qsum*a)%mod;
b>>=;
a=(a*a)%mod;
}
return qsum;
} //测试x较小的情况,必须!
ll firsttest(ll A,ll B,ll C)
{
ll tmp=;
if(B==) return ;
for(int i=;i<;i++)
{
tmp = (tmp*A)%C;
if(tmp==B) return i;
}
return -;
} ll BabyStep(ll A,ll B,ll C,ll OC)
{
if(==A || ==C) return -;
if(C==) return ;
B = B%C;
ll ans = firsttest(A,B,C);//为了防止x比较小的时候
if(ans != -) return ans;
ll D=;
int c=;
ll d;
while( (d=gcd(A,C)) != )
{
if( B%d != ) return -;//无解的情况
B /= d;
C /= d;
D = D*A/d%C;
c++;
} //得到了 D*A^(x-c)=B (mod C) ,gcd(A,C)=1 , gcd(D,C)=1
ll D_1=GetNi(D,C);//求D的逆元
B = B*D_1%C;
//求A^x=B (mod C),然后返回x+c
ll m = ceil( sqrt(C+0.0) ); memset(hashpre,-,sizeof(hashpre));
hashcnt=;
ll hashnum=;
hash_insert(, , );
for(int i=;i<m;i++)
{
hashnum = (hashnum*A)%C;
hash_insert(hashnum%HASH_N, hashnum ,i);
} ll ol=OC;//这一步可以省略
ll mA=Quk_Mul(A, m, C);
ll ta=; ll tmpni = Quk_Mul(mA, ol-, C); for(int i=;i<m;i++,ta=ta*tmpni%C)
{
//解线性同余方程 tx=B*ta (%C) ,ta直接用费马小定理求逆元
ll tx = ta;
tx = (tx*B)%C;
int j=hash_get(tx);
if(j!=-)//找到解了
{
return i*m+j+c;
}
} return -;
} ll mypow(ll a,ll b)
{
ll sum=;
for(int i=;i<=b;i++)
sum*=a;
return sum;
} ll slove(ll a,ll b,ll c,ll p,int a1)
{
//第0种情况a==1
if(a==) return ; //第一种情况b==c
b %= c;
if(b==)
{
ll tmp = mypow(p,ceil( (double)a1/a ) );
return c/tmp;
}
ll d=gcd(b,c);
//第二种情况 gcd(b,c)!=1
if( d != )
{
return ;
} //第三种情况 gcd(b,c)==1 //第一步找出原根x0,
ll save[];
int cnt=; ll tc = mypow(p,a1-)*(p-);
for(ll i=;i*i<=tc;i++)
{
if(tc%i == )
{
save[ cnt++ ] = i;
while(tc%i==) tc/=i;
}
}
if(tc != )
{
save[ cnt++ ] = tc;
}
tc= mypow(p,a1-)*(p-);
for(int i=;i<cnt;i++)
{
save[i] = tc/save[i];
} ll x0=;
for(int i=;i<c;i++)
{
int flag=;
for(int j=;j<cnt;j++)
{
if( Quk_Mul(i, save[j], c) ==)
{
flag=;
break;
}
}
if(flag==)
{
x0=i;
break;
}
}
//找到原根x0后,然后找x0^a0 = b (mod c)
ll a0 = BabyStep(x0 , b, c,mypow(p,a1-)*(p-));
ll ord = mypow(p,a1-)*(p-);
d = gcd(a,ord);
if( a0%d != ) return ;
return d;
} ll xaeqbmodc(ll a,ll b,ll c)
{
ll ans=;
b%=c;
ll tc=c;
//然后对c进行因式分解
for(ll i=;i*i<=tc;i++)
{
if(tc%i==)
{
ll tmpyz=;
int a1=;
while(tc%i==)
{
a1++;
tmpyz *= i;
tc/=i;
}
//然后对这个因子进行处理
ans *= slove(a,b,tmpyz,i,a1);
if(ans==) break;
}
}
if(tc!=)
{
ans *= slove(a,b,tc,tc,);
}
return ans;
}
其实这就是hdu3731了,关于思路可惜不是完全自己想的,稍微瞟了一眼大神的做法,突破了自己原先思维中不敢动c的想法,然后这题就会做了。这题A了也表示数论算是入了个门了,记得XIANBIN5在大一的时候就把数论学完了,并且把这题A了,我还是差太多啊。 接下来就是计算几何了。
以下来自:http://www.cnblogs.com/dyllove98/archive/2013/08/05/3239030.html
求方程:的解个数
分析:设,那么上述方程解的个数就与同余方程组:
的解等价。
设同于方程的解分别是:,那么原方程的解的个数就是
所以现在的关键问题是求方程:的解个数。
这个方程我们需要分3类讨论:
第一种情况:
对于这种情况,如果方程的某个解设为,那么一定有
,可以得到
,即
所以方程的解个数就是:,也就是
第二种情况:
这样也就是说p|B,设,
,本方程有解的充要条件是A|t,
那么我们设t=kA,
所以进一步有:,因为
,这样又转化为第三种情况了。
第三种情况:
那么我们要求指标;求指标的话又要求原根。并且奇素数p的原根也是p^a的原根,所以说求个p的原根就好了。
且如果有解,则解的个数为(A,φ(p^a))。
求指标的话就是要解决A^x ≡ B (mod p^a)的问题。由于本情况保证了(p^a, B)=1,用个Baby-step-Giant-step就
能解决问题。
方程x^A ≡ B (mod p^a)有解,当且仅当(A,φ(p^a))|ind B。ind B表示B对于p^a的任一原根的指标。
x^a=b(mod c)求解x在[0,c-1]上解的个数模板+原根求法的更多相关文章
- HDU 4622 求解区间字符串中的不同子串的个数
题目大意: 给定一个长度<2000的串,再给最多可达10000的询问区间,求解区间字符串中的不同子串的个数 这里先考虑求解一整个字符串的所有不同子串的方法 对于后缀自动机来说,我们动态往里添加一 ...
- 算法实践——舞蹈链(Dancing Links)算法求解数独
在“跳跃的舞者,舞蹈链(Dancing Links)算法——求解精确覆盖问题”一文中介绍了舞蹈链(Dancing Links)算法求解精确覆盖问题. 本文介绍该算法的实际运用,利用舞蹈链(Dancin ...
- 【bzoj2219-数论之神】求解x^a==b(%n)-crt推论-原根-指标-BSGS
http://www.lydsy.com/JudgeOnline/problem.php?id=2219 弄了一个晚上加一个午休再加下午一个钟..终于ac..TAT 数论渣渣求轻虐!! 题意:求解 x ...
- 转载 - 算法实践——舞蹈链(Dancing Links)算法求解数独
出处:http://www.cnblogs.com/grenet/p/3163550.html 在“跳跃的舞者,舞蹈链(Dancing Links)算法——求解精确覆盖问题”一文中介绍了舞蹈链(Dan ...
- 龙哥库塔法or欧拉法求解微分方程matlab实现
举例:分别用欧拉法和龙哥库塔法求解下面的微分方程 我们知道的欧拉法(Euler)"思想是用先前的差商近似代替倒数",直白一些的编程说法即:f(i+1)=f(i)+h*f(x,y)其 ...
- 蚁群算法求解旅行商问题(附c和matlab源代码)
前几天写了个模拟退火算法的程序,然后又陆陆续续看了很多群智能算法,发现很多旅行商问题都采用蚁群算法来求解,于是开始写蚁群算法的模板.网上关于蚁群算法的理论很多就不再这里赘述了,下面直接上代码和进行简单 ...
- HDOJ 4389 X mod f(x)
数位DP........ X mod f(x) Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/ ...
- C++线性方程求解
介绍 程序SolveLinearEquations解决联立方程.该方案需要一个文本文件,其中包含输入和输出方程解决.这个项目是几年前我写在C#中http://www.codeproject.com/A ...
- HDU4389:X mod f(x)(数位DP)
Problem Description Here is a function f(x): int f ( int x ) { if ( x == 0 ) return 0; return f ( x ...
随机推荐
- kubernetes1.5.2--部署DNS服务
本文基于kubernetes 1.5.2版本编写 在kubernetes1.2之前,采用skydns+kube2dns+etcd的方式来部署dns.而从1.3开始,则部署方式有了一点儿变化,将skyd ...
- 转换流的使用(InputStreamReader,OutputStreamWriter)
我们如何设置字节输入流.字节输出流的编码和解码格式? 在字节输入流(InputStream).字节输出流(OutputStream)中,并没有提供设置编码和解码格式的方法. InputStream的A ...
- jstat命令的使用及VM Thread分析
http://www.javatang.com/archives/2017/10/20/12131956.html 前面提到了一个使用jstack的shell脚本,通过命令可以很快地定位到指定线程对应 ...
- selenium实现失败重运行
UI自动化脚本执行过程中存在非常多的不稳定性,例如网络的不稳定,浏览器无响应等等,这些失败往往并不是产品中的错误.那么这时我们往往需要对执行失败的测试用例进行多次重跑,确认其是否确实失败. 那么失败重 ...
- Win10 导航窗口不能移动文件win10 资源管理器 无法拖动文件到左侧驱动器
Win10 导航窗口不能移动文件怎么办 Win10左侧导航栏不能移动文件怎么办 win10 资源管理器 无法拖动文件到左侧驱动器怎么办 在同一个文件夹可以拖动来移动文件,拖到地址栏的面包屑也可以移动文 ...
- JavaScript实现深拷贝(深复制) 面试题
1.两种方法实现深拷贝(深复制) (1)方法一:兼容性好,请仔细看代码(网上大部分代码有Bug) (2)方法二:需要对象满足JSON数据格式.JOSN数据格式:http://www.cnblogs.c ...
- 【Excle数据透视表】如何让字段标题不显示“求和项”
我们做好了数据透视表之后是下面这个样子的 这个样子一点都不好看,那么如何去掉"求和项"呢? 步骤 方法① 单击B3单元格→编辑区域输入"数量 "→Enter(也 ...
- Loadrunner中对中文进行UTF-8转码的探索
上一篇 / 下一篇 2010-02-22 15:20:28 查看( 2378 ) / 评论( 2 ) / 评分( 5 / 0 ) 这是一个HTTP接口测试中经常会碰到的问题,目前的服务器采用的都是U ...
- Cookie-Parser是怎样解析签名后的cookie的(同一时候对cookie和cookie-signature进行说明)
第一步:我们来学习一下cookie-signature: var cookie=require('./index'); var val = cookie.sign('hello', 'tobiisco ...
- Lua学习十一----------Lua迭代器
© 版权声明:本文为博主原创文章,转载请注明出处 Lua迭代器 - 迭代器(iterator)是一种对象,它能够用来遍历标准模板库容器中的部分或全部元素,每个迭代器对象代表容器中的确定的地址 - Lu ...