二次剩余-学习笔记
二次剩余是干什么的?简单的说就是模意义下开根号:
P为2的情况
解为
P为奇素数的情况
勒让德符号:
如何求值?
定理:
证明:
当a在模p意义下是二次剩余时,令
当a在模p意义下不是二次剩余时,依旧令
当
因此首先判断有解:
然后找到一个a,使得
证明:
首先证明
由于n是质数,因此当i不等于0且不等于n的时候,组合数阶乘公式中的n是没有办法被消掉的,就会被模成0,因此这些项都是对答案没有贡献的。而i=0或i=n时,我们就分别可以得到
如何求
就像
如何保证最终快速幂的结果虚部为0?
根据拉格朗日定理,我们知道在任意一个模
由此问题完美解决,算法时间复杂度是
还有一个问题如何找到a?方法是随机!因为概率大概是
struct F
{
int x,y;
F() {}
F(const int &xx,const int &yy)
{
x=xx,y=yy;
}
friend F operator*(const F &a,const F &b)
{
return F(((LL)a.x*b.x%md+(LL)a.y*b.y%md*w%md)%md,((LL)a.x*b.y%md+(LL)a.y*b.x%md)%md);
}
};
F qpow(F a,int b)
{
F res(1,0);
for(; b; b>>=1,a=a*a) if(b&1) res=res*a;
return res;
}
int qpow(int a,int b)
{
int res=1;
for(; b; b>>=1,a=(LL)a*a%md) if(b&1) res=(LL)res*a%md;
return res;
}
int solve(int n)
{
if(md==2) return 1;
if(qpow(n,(md-1)/2)==md-1) return -1;
while(1)
{
int a=rand()%md;
w=((LL)a*a%md-n+md)%md;
if(qpow(w,(md-1)/2)==md-1)
{
F ans=qpow(F(a,1),(md+1)/2);
return ans.x;
}
}
}
P为奇素数的幂
Blog
N次剩余
借助离散对数。
Blog