标签:处理 整数 for 预处理 注意 最小 暴力枚举 ++ 欧拉定理
\(gcd\):
inline int gcd(int a,int b){ return b?gcd(b,a%b):a;}
扩展欧几里得:求\(ax+by=gcd(a,b)\)的一组整数解。
inline int Exgcd(int a,int b,int &x,int &y)
{
if(!b) {x=1,y=0;return a;}
int Gcd=Exgcd(b,a%b,y,x);
y-=a/b*x;return Gcd;
}
费马小定理:\(a^{p-1}\equiv 1\mod p\)(\(p\)为质数)
欧拉定理(\(gcd(a,n)\ne 1\)):(無駄?)
\[
a^b\equiv \left\{\begin{array}{ll} a^b & b<\varphi(n)\\a^{b\mod\varphi(n)+\varphi(n)} & b\geq \varphi(n)\end{array}\right.\mod n
\]
欧拉定理(\(gcd(a,n)=1\)):\(a^{\varphi(n)}\equiv 1\mod n\)(無駄?)
中国剩余定理(孙子定理):\(p_1,p_2,p_3...p_k\)两两互质,求一下方程组的最小整数解
\[
\left\{\begin{array}{ll}x\equiv a_1\mod p_1\\x\equiv a_2\mod p_2\\...\\x\equiv a_k\mod p_k\end{array}\right.
\]
令\(P=\prod p_i\),\(P_i=\frac{P}{p_i}\),\(t_i,P_i\)满足\(t_iP_i\equiv1\mod p_i\)。
所以最小整数解为:\(x=\sum a_iP_it_i \mod P\)。
inline int Exgcd(int a,int b,int &x,int &y)
{
if(!b) {x=1,y=0;return a;}
int Gcd=Exgcd(b,a%b,y,x);
y-=a/b*x;return Gcd;
}
int main(){
n=read();
for(int i=1;i<=n;i++) p[i]=read(),a[i]=read(),P*=p[i];
for(int i=1;i<=n;i++)
{
int Pi=P/p[i],x,y;Exgcd(Pi,p[i],x,y);
ans=(ans+a[i]*Pi*((x%p[i]+p[i])%p[i]))%P;
}
printf("%lld",ans);
}
扩展中国剩余定理(儿子定理)\(p_1,p_2,p_3...p_k\)不一定两两互质,求一下方程组的最小整数解
\[
\left\{\begin{array}{ll}x\equiv a_1\mod p_1\\x\equiv a_2\mod p_2\\...\\x\equiv a_k\mod p_k\end{array}\right.
\]
考虑两个式子:\(x\equiv a_1 \mod p_1,x\equiv a_2\mod p_2\)合并(这里是完整的推导过程)注意不同部分的模数因为其来源可能不同
可以合并成:\(x\equiv a'\mod m'\)。其中\(a'=p_1[inv(\frac{p_1}{gcd},\frac{p_2}{gcd})\frac{a_2-a_1}{gcd}\%\frac{p_2}{gcd}]+a_1,m'=\frac{p_1p_2}{gcd}\)(\(gcd=gcd(p_1,p_2),inv(x,y)\)表示\(x\)在模\(y\)意义下的逆元,\(y\)不一定为质数,所以要用\(Exgcd\)求)
inline int gcd(int x,int b) {return b?gcd(b,x%b):x;}
inline int Exgcd(int a,int b,int &x,int &y)
{
if(!b) {x=1,y=0;return a;}
int Gcd=Exgcd(b,a%b,y,x);
y-=a/b*x;return Gcd;
}
inline int Inv(int a,int b){int x,y;Exgcd(a,b,x,y);return (x%b+b)%b;}
signed main(){
int Jud=0;n=read();
for(int i=1;i<=n;i++) p[i]=read(),a[i]=read();
for(int i=2;i<=n;i++)
{
int Gcd=gcd(p[i],p[i-1]),Now,p1=p[i-1],p2=p[i],a1=a[i-1],a2=a[i];
Now=Inv(p1/Gcd,p2/Gcd)%(p2/Gcd);
Now=(Now*(((a2-a1)/Gcd)%(p2/Gcd))%(p2/Gcd)+(p2/Gcd))%(p2/Gcd);
Now=((Now%(p2*p1/Gcd)*p1%(p2*p1/Gcd))%(p2*p1/Gcd)+(p2*p1/Gcd))%(p2*p1/Gcd);
Now=(Now%(p2*p1/Gcd)+a1%(p2*p1/Gcd))%(p2*p1/Gcd);
p[i]=p2*p1/gcd(p2,p1); a[i]=(Now%p[i]+p[i])%p[i];
}
print(Jud?-1:a[n]);
}
\(BSGS\):求\(A^x\equiv B\mod C\)的\(x\)。(满足\(gcd(A,C)=1\))
设\(m=\sqrt{C}\),令\(x=am+b\),所以有\(A^{am}\equiv A^bB\mod C\),预处理\(A^b\),暴力枚举\(a\)即可。
int m=sqrt(C)+1,now=1;
for(int i=0;i<m;i++)mp[(now*B)%C]=i,now=((now%C)*(A%C))%C;
k=((k%C)*(now%C))%C;
for(int i=1;i<=m;i++)
{
if(mp[k]) return ((i%C)*(m%C)-mp[k]+C)%C;
k=((k%C)*(now%C))%C;
}
扩展\(BSGS\):求\(A^x\equiv B\mod C\)的\(x\)。(不一定满足\(gcd(A,C)=1\))
令\(d=gcd(A,C)\),则我们可以除掉\(d\),原始变为\(\frac{A}{d}A^{x-1}\equiv \frac{B}{d}\mod \frac{C}{d}\),不断检查\(gcd(\frac{z}{d},y)\),一直除到互质为止,最后将减掉的补回来就行了。
inline int EXBSGS(int A,int B,int C)
{
int cnt=0,d,k=1;
while((d=gcd(A,C))^1)
{
if(B%d) return -1;
B/=d;C/=d;++cnt;
k=(k*(A/d))%C;
if(k==B) return cnt;
}
mp.clear();int m=sqrt(C)+1,now=1;
for(int i=0;i<m;i++) mp[(now*B)%C]=i,now=(now*A)%C;
k=(k*now)%C;
for(int i=1;i<=m;i++)
{
if(mp[k]) return (cnt+i*m-mp[k]+C)%C;
k=(k*now)%C;
}
return -1;
}
线性筛:(不多讲,直接上)
inline void Make_Prime(int T)
{
Vis[1]=1;
for(int i=2;i<=T;i++)
{
if(!Vis[i]) Pri[++Cnt]=i;
for(int j=1;j<=Cnt&&i*Pri[j]<=T;j++)
{
Vis[i*Pri[j]]=1;
if(!(i%Pri[j])) break;
}
}
}
\(Miller\) \(Rabin\):
前置定理:费马小定理,二次探测:若\(a^2\equiv 1\mod p\)且\(p\)为质数,则\(a\equiv1\)或\(p-1\mod p\)。
假设我们判定\(x\),将其拆为\(x=2^kt\)形式,随即一个\(a\)并求出\(a^t\),然后依次将\(2\)乘上去,用二次探测即可。
最好我们多测几次\(Miller\) \(Rabin\)。
int Tex[4]={2,3,5,7};
inline int ksm(int b,int k,int p)
{
int a=b; k--;
while(k)
{
if(k&1) a=(a%p*b%p+p)%p;
b=(b%p*b%p+p)%p;k>>=1;
}
return a%p;
}
inline bool Miller_Rabin(int x)
{
if(x==1) return 0;
int Now=x-1,k=0;
while(!(Now&1)) Now>>=1,k++;
for(int i=0;i<4;i++)
{
int a=ksm(Tex[i],Now,x)%x,Nex=a;
if(x==Tex[i]) return 1;
for(int j=1;j<=k;j++)
{
Nex=(a%x*a%x+x)%x;
if(Nex==1&&a!=1&&a!=x-1) return 0;
a=Nex;
}
if(a!=1) return 0;
}
return 1;
}
\(Lucas\):懒得证明了,记着:\({n \choose m}\%p={n\%p \choose m\%p}*{n/p \choose m/p}\%p\)
inline int ksm(int b,int k)
{
int a=b;k--;
while(k)
{
if(k&1) a=(a%p*b%p)%p;
b=(b%p*b%p)%p;k>>=1;
}
return a%p;
}
inline int C(int n,int m)
{
if(m>n) return 0;
return (Fac[n]%p*ksm((Fac[m]%p*Fac[n-m]%p)%p,p-2)%p)%p;
}
inline int Lucas(int n,int m)
{
if(!m) return 1;
return (C(n%p,m%p)%p*Lucas(n/p,m/p)%p)%p;
}
标签:处理 整数 for 预处理 注意 最小 暴力枚举 ++ 欧拉定理
原文地址:https://www.cnblogs.com/wo-shi-zhen-de-cai/p/11623355.html