http://www.lydsy.com/JudgeOnline/problem.php?id=2219

弄了一个晚上加一个午休再加下午一个钟。。终于ac。。TAT

数论渣渣求轻虐!!

题意:求解 x^A=B(mod n) 在0~n内解的个数。其中1 <= A, B <= 10^9, 1 <= K <= 5 * 10^8  (n=2*K+1)

首先先说这一题的弱化版:bzoj1319 http://www.lydsy.com/JudgeOnline/problem.php?id=1319

bzoj1319这题是保证了P为质数。

找到p的一个原根g,因为g^x构成一个缩系,g^x可以表示0~p-1所有数。
g^j=a(%p), g(%p)=1, (g^i)^k=1(%p)
g^ik=g^j (%p)
ik=j(%phi(p))
用BSGS求出j,exgcd求出所有i,x就是g^i。

分析这一题:P不一定是质数。

取模数不是质数,无法利用通常的方式解方程;

但是有中国剩余定理这个东西,定理的推论告诉我们:

一个取模数互质的同余方程组(未必线性),组合起来之后,这个同余方程解的个数为各方程解的个数的乘积

(组合起来的方程的取模数为所有数的积;实际上这里解的范围都是属于[0 ,自己取模数) )

这点十分重要呢,它不仅证明了解的求法,而且如果有任意一个方程无解,那么整个就都是无解的;

————引用自http://blog.csdn.net/ww140142/article/details/47814003

把n分解质因数。

接下来我们只需要处理方程x^A==B(%p^a)

再次引用题解。。只有第三种情况是我自己搞的。。

引用自大牛http://blog.csdn.net/regina8023/article/details/44863519

但是第三种情况我没看懂它怎么搞。。

这个时候就可以用bzoj1319的解法了!

找到p^a的一个原根g,因为g^x构成一个缩系,g^x可以表示0~p^a-1所有数。

有一个推论(我也不知道为什么)g是p的原根,则g是p^a的原根。就可以很快找出来啦。

解释一下情况1和情况2为什么范围扩大之后就直接乘:

例如情况1:t=(a-1)/A+1,[0,p^t]中有一个解,范围[0,p^a)中有p^(a-t)个这样的范围。

假设p^t就是解。那下一个小区间中的p^(2t)也是解,以此类推。

PS:找原根的方法:

 预判n有没有原根,有原根的数为:、、、P^a,*P^a,P为任意奇素数

 快速求所有原根:
m=phi(n)
找到m所有的质因子y
找出n最小的原根a:gcd(a,n)== && a^(m/y) %n都!=
则a^x%n(<=x<m,gcd(x,m)==) 是n所有原根。

依照上题,化成

g^ik=g^j (%p^a)
ik=j(%phi(p^a))
用BSGS求出j,解i的个数就是答案。

这里又有一个可爱的推论。。我还是不知道为什么。。

ax-py=gcd(a,p)

解的个数为gcd(a,p)。

然后这题就做完了。

 #include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std; typedef long long LL;
const LL N=,Inf=(LL)1e12;
struct node{LL d,id;}num[N];
LL nl,fl,pxl,px[N],r[N],f[N]; void find_px(LL n)
{
pxl=;
for(LL i=;i*i<=n;i++)
{
if(n%i==) px[++pxl]=i,r[pxl]=;
while(n> && n%i==) n/=i,r[pxl]++;
if(n==) break;
}
if(n>) px[++pxl]=n,r[pxl]=;//debug
} LL gcd(LL a,LL b)
{
if(b==) return a;
return gcd(b,a%b);
} LL quickpow(LL x,LL y,LL n)
{
LL ans=%n;
while(y)
{
if(y&) ans=(ans*x)%n;
x=(x*x)%n;y>>=;
}
return ans;
} bool cmp(node x,node y){
if(x.d!=y.d) return x.d<y.d;
return x.id<y.id;
} LL find_j(LL t)
{
LL l=,r=nl,mid;
while(l<=r)
{
mid=(l+r)>>;
if(num[mid].d==t) return num[mid].id;
if(num[mid].d<t) l=mid+;
if(num[mid].d>t) r=mid-;
}
return -;
} LL BSGS(LL a,LL b,LL n,LL phi)//a^x==b(%n)
{
LL m,x,am,now,t;
m=(LL)ceil(sqrt((double)n));
x=%n;
nl=;num[++nl].d=,num[nl].id=;
for(int i=;i<=m;i++)
{
x=(x*a)%n;
num[++nl].d=x;num[nl].id=i;
}
am=x;
sort(num+,num++nl,cmp);
now=;
for(int i=;i<=nl;i++)
{
if(num[i].d!=num[i-].d) num[++now]=num[i];
}
nl=now;
am=quickpow(am,phi-,n);
t=b%n;
for(int i=;i<=m;i++)
{
x=find_j(t);
if(x!=-) return i*m+x;
t=(t*am)%n;
}
return -;
} LL find_root(LL p)
{
LL x=p-;
fl=;
for(int i=;i*i<=p-;i++)
{
if((p-)%i==) f[++fl]=i,f[++fl]=(p-)/i;//debug不是找质因子啊。。
}
for(int i=;i<p-;i++)
{
bool bk=;
for(int j=;j<=fl;j++)
if(quickpow(i,(p-)/f[j],p)==) {bk=;break;}
if(bk) return i;
}
} LL solve_3(LL A,LL B,LL p,LL a)
{
LL phi,g,gc,j,pa;
pa=quickpow(p,a,Inf);
phi=(p-)*quickpow(p,a-,Inf);
g=find_root(p);
j=BSGS(g,B,pa,phi);
gc=gcd(A,phi);
// printf("phi = %lld j = %lld g = %lld pa = %lld\n",phi,j,g,pa);
// printf("s3 %lld %lld %lld %lld = %lld\n\n",A,B,p,a,gc);
if(j%gc) return ;
return gc;
} LL solve(LL A,LL B,LL p,LL a)
{
LL g,pa,x,y,b,cnt;
pa=quickpow(p,a,Inf);
g=gcd(pa,B);
//case 1
if(B%pa==) return quickpow(p,a-(((a-)/A)+),Inf);
//case 2
if(g>)
{
b=B/g;
cnt=;x=g;
while(x%p==) x/=p,cnt++;
if(cnt%A) return ;
return solve_3(A,b,p,a-cnt)*quickpow(p,cnt-(cnt/A),Inf);
}
//case 3
return solve_3(A,B,p,a);
} int main()
{
freopen("a.in","r",stdin);
// freopen("me.out","w",stdout);
int T;
scanf("%d",&T);
LL A,B,n,ans;
while(T--)
{
scanf("%lld%lld%lld",&A,&B,&n);
n=*n+;
find_px(n);
ans=;
for(LL i=;i<=pxl;i++)
{
ans*=solve(A,B,px[i],r[i]);
if(ans==) break;
}
printf("%lld\n",ans);
}
return ;
}

【bzoj2219-数论之神】求解x^a==b(%n)-crt推论-原根-指标-BSGS的更多相关文章

  1. bzoj2219: 数论之神

    #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #i ...

  2. BZOJ2219数论之神——BSGS+中国剩余定理+原根与指标+欧拉定理+exgcd

    题目描述 在ACM_DIY群中,有一位叫做“傻崽”的同学由于在数论方面造诣很高,被称为数轮之神!对于任何数论问题,他都能瞬间秒杀!一天他在群里面问了一个神题: 对于给定的3个非负整数 A,B,K 求出 ...

  3. BZOJ2219 数论之神 数论 中国剩余定理 原根 BSGS

    原文链接https://www.cnblogs.com/zhouzhendong/p/BZOJ2219.html 题目传送门 - BZOJ2219 题意 求同余方程 $x^A\equiv B \pmo ...

  4. 【BZOJ】【2219】数论之神

    中国剩余定理+原根+扩展欧几里得+BSGS 题解:http://blog.csdn.net/regina8023/article/details/44863519 新技能get√: LL Get_yu ...

  5. 数论算法 剩余系相关 学习笔记 (基础回顾,(ex)CRT,(ex)lucas,(ex)BSGS,原根与指标入门,高次剩余,Miller_Rabin+Pollard_Rho)

    注:转载本文须标明出处. 原文链接https://www.cnblogs.com/zhouzhendong/p/Number-theory.html 数论算法 剩余系相关 学习笔记 (基础回顾,(ex ...

  6. 牛客国庆集训派对Day5 数论之神

    题目描述 终于活成了自己讨厌的样子. 这是她们都还没长大的时候发生的故事.那个时候,栗子米也不需要为了所谓的爱情苦恼. 她们可以在夏日的午后,花大把的时间去研究生活中一些琐碎而有趣的事情,比如数论. ...

  7. BZOJ 2219 数论之神 (CRT推论+BSGS+原根指标)

    看了Po神的题解一下子就懂了A了! 不过Po神的代码出锅了-solve中"d-temp"并没有什么用QwQQwQQwQ-应该把模数除以p^temp次方才行. 来自BZOJ讨论板的h ...

  8. 【hdu 3579】Hello Kiki(数论--拓展欧几里德 求解同余方程组)

    题意:Kiki 有 X 个硬币,已知 N 组这样的信息:X%x=Ai , X/x=Mi (x未知).问满足这些条件的最小的硬币数,也就是最小的正整数 X. 解法:转化一下题意就是 拓展欧几里德求解同余 ...

  9. 【poj 2891】Strange Way to Express Integers(数论--拓展欧几里德 求解同余方程组 模版题)

    题意:Elina看一本刘汝佳的书(O_O*),里面介绍了一种奇怪的方法表示一个非负整数 m .也就是有 k 对 ( ai , ri ) 可以这样表示--m%ai=ri.问 m 的最小值. 解法:拓展欧 ...

随机推荐

  1. 安装Sql Server 2008的时候报错说找不到某个安装文件

           在安装Sql Server 2008的时候,报错说找不到某个安装文件,但是这个文件明明在那,百思不得其解.           最后看到一个老外的文章里面说,你要确认,你能访问到这个文件 ...

  2. Accept 惊群现象测试perl脚本

    $uname -a Linux debian-11-34 3.16.0-4-amd64 #1 SMP Debian 3.16.7-ckt9-3~deb8u1 (2015-04-24) x86_64 G ...

  3. Spring常用注解用法总结

    转自http://www.cnblogs.com/leskang/p/5445698.html 1.@Controller 在SpringMVC 中,控制器Controller 负责处理由Dispat ...

  4. Qt 使用irrlicht(鬼火)3D引擎

    项目中需要加载简单的3D场景.资深老前辈推荐使用开源小巧的引擎irrlicht. 关于irrlicht,来之百度百科 Irrlicht引擎是一个用C++书写的高性能实时的3D引擎,可以应用于C++程序 ...

  5. 最短路径——Floyd算法(含证明)

    通过dij,ford,spfa等算法可以快速的得到单源点的最短路径,如果想要得到图中任意两点之间的最短路径,当然可以选择做n遍的dij或是ford,但还有一个思维量较小的选择,就是floyd算法. 多 ...

  6. 最短路径——Bellman-Ford算法以及SPFA算法

    说完dijkstra算法,有提到过朴素dij算法无法处理负权边的情况,这里就需要用到Bellman-Ford算法,抛弃贪心的想法,牺牲时间的基础上,换取负权有向图的处理正确. 单源最短路径 Bellm ...

  7. mysql原理以及相关优化

    说起MySQL的查询优化,相信大家积累一堆技巧:不能使用SELECT *.不使用NULL字段.合理创建索引.为字段选择合适的数据类型..... 你是否真的理解这些优化技巧?是否理解其背后的工作原理?在 ...

  8. WCF扩展记录服务调用时间

    WCF 提供了许多扩展点供开发人员自定义运行时行为. WCF 在 Channel Layer 之上还提供了一个高级运行时,主要是针对应用程序开发人员.在 WCF 文档中,它常被称为服务模型层(Serv ...

  9. 使用ExecutorService实现线程池

    ExecutorService是java提供的用于管理线程池的类. 线程池的作用: - 控制线程数量 - 重用线程 当一个程序中创建了许多线程,并在任务结束后销毁,会给系统带来过度消耗资源,以及过度切 ...

  10. P4109 [HEOI2015]定价

    题目描述 在市场上有很多商品的定价类似于 999 元.4999 元.8999 元这样.它们和 1000 元.5000 元和 9000 元并没有什么本质区别,但是在心理学上会让人感觉便宜很多,因此也是商 ...