【复习】幼儿园数论复习
害怕
扩欧
因为ax1+by1==gcd(a,b) bx2+(a%b)y2==gcd(a,b) 所以ax1+by1==bx2+(a%b)y2所以ax1+by1==bx2+(a-(a/b)b)y2所以ax1+by1==ay2+b(x2-(a/b)y2),所以x1==y2,y1==(x2-(a/b)*y2)//exgcd
int exgcd(int a,int b,int &x,int &y) {
if(!b) {
x=1; y=0; return a;
}
int xx,yy;
int tmp=exgcd(b,a%b,xx,yy);
x = yy; y = (xx-(a/b)*yy);
return tmp;
}
中国剩余定理(不扩展)
对于一个同余方程组例如 X==a1(mod m1) X==a2(mod m2) X==a3(mod m3) ..... X==an(mod mn) 就是点兵那个玩意,并且有m1,m2,m3,....mn互质的话,就可得出最小的正整数解X。 我们设定P为m1m2m3...mn,那么Mi为M/mi,那么就有 X==(M1(M1在模m1意义下的逆元)a1 + M2(M2在m2意义下的逆元)a2 + M3(M3在模m3意义下的逆元)*a3.....)%P。扩展中国剩余定理
说实话,这玩意和孙子定理的区别还是有些大的,,唯一的相同点就是这两个用来解决对问题是一样的(感觉扩中比普中简单?orzorz),而这东东适用范围更广,可以适用于m1,m2,m3....mn不互质的情况。 例如我们针对两个线性方程组 X==a1 ( mod b1) X==a2 ( mod b2) 我们将两个式子展开 X=b1x1 + a1,X=b2x2 + a2,那么有b1x1 + a1=b2x2 + a2,那么我们移项b1x1+b2x2=a2-a1(因为我们知道x2是一个未知数,由于除了扩欧求解的时候用到之后不会用到,那么我们不变号),该请出扩欧啦,我们求出最小的正整数解x1,将这个x1代入b1*x1+a1=K(我们设得到的数为K),那么我们就合并得到了一个新的方程组X==K(mod lcm(b1,b2))(lcm为最小公倍数),我们一直合并下去,最后得到的那个K就是答案啦!欧拉线性筛
代码说话#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn = 10000005;
int cnt,pri[maxn];//有那些质数
bool ispri[maxn];//i是否是质数
int mindiv[maxn];//i的最小质因子
int phi[maxn];//i的欧拉函数
int mindivq[maxn];//i的最小质因子个数
int d[maxn];//i的约数个数
int sumd[maxn];//i的约数和
int sp[maxn];//i的最小素因子的等比数列和(1+p+p^2+p^3)(为了方便计算约数和用)
int miu[maxn];//i的莫比乌斯函数
void eula(int n)
{
ispri[1]=ispri[0]=0;
miu[1]=1;
memset(ispri,1,sizeof ispri);
for(int i=2;i<=n;i++)
{
if(ispri[i])
{
pri[++cnt]=mindiv[i]=i;//这个数是质数且其最小质因子为本身 }
phi[i]=i-1;//质数i的欧拉函数为i-1
miu[i]=-1;//有一个本质不同的质因数
sumd[i]=i+1;//质数约数和显然本身和1
sp[i]=i+1;
}
for(int j=1;j<=cnt&&pri[j]*i<=n;j++)
{
int k = i*pri[j];
ispri[k]=0;
mindiv[k]=pri[j];//每个数只会被最小的质因数筛掉
if(i%pri[j]==0)
{
phi[k]=phi[i]*pri[j];//对于一个数是另一个数的倍数其欧拉函数有倍数关系
mindivq[k]=mindivq[i]+1;//与i有相同的最小质因数且为i倍数
d[k]=d[i]/(mindivq[i]+1)*(mindivq[k]+1);//我们在i的基础上又乘了一个最小的质因数,因为d[i]=求积(pri_i个数+1)(pri_i为分解的质因数),这么一来这就很显然啦
miu[k]=0;//有一个质因子的个数起码为2,miu为0
sp[k]=sp[i]*pri[j]+1//类比秦九韶
sum[k]=sum[i]/sp[i]*sp[k];//去除最小质因子的等比数列之后乘上当前的等比数列
break;
}
phi[k]=phi[i]*phi[pri[j]];//对于两个互质的数的欧拉函数有积性性质,pri[j]显然与i互质
mindivq[k]=1;//可怜只有一个
d[k]=d[i]*d[pri[j]];//约数个数是显然的积性函数
miu[k]=-miu[i];//多了一个本质不同的质因数
sumd[k]=sumd[i]*sumd[pri[j]];//多了一个本质不同质因数就多*(1+p)
sp[k]=1+pri[j];//显然只有1和pri[j]
}
}
}
int main()
{
eula(1000000);
for(int i=1;i<=20;i++) cout<<pri[i]<<" ";
}
我们发现欧拉筛可以筛约数和。其原理是某个数的约数和为(1+p1+p1^2+p1^3.....)(1+p2+p2^2+p2^3+p2^4+....)(1+p3+p3^2+p3^3+p3^4+....)...*(1+pn+pn^2+....pn^k)这个p和k是在唯一分解完后的质因数和质因数上的指数。
miller_rabin
由于质数,那么对于x^(n-1)%n一定等于1,那么我们将n-1分解成2^r*d,然后之后一个个判断就可以了。(其实其中还有很多细节,详见code)#include<algorithm>
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
ll xy[20] = {0,2,3,5,7,11,13,17,19,61,0};
/*
ll ksc(ll a,ll b,ll mod) {
ll ans = 0;
for(a%=mod;b;b>>=1,a=(a+a)%mod) {
if(b&1) ans = (ans+a)%mod;
}
return ans;
}
*/
ll ksc(ll a,ll b,ll n) {
ll tmp = a*b - ((ll)((long double)a/n*b+0.5) )*n;
return tmp<0?tmp+n:tmp;
}
ll ksm(ll a,ll b,ll mod) {
ll ans = 1;
for(;b;b>>=1,a=ksc(a,a,mod))
if(b&1) ans = ksc(ans,a,mod);
return ans;
}
bool miller_rabin(ll n) {
ll x,y,r=0,d;
if(n==2) return 1;
if(n<2||n%2==0) return 0;
d = n-1;
while(d%2==0) d/=2,r++;
for(ll i=1;i<=9;i++) {
if(xy[i]==n) return 1;
ll x = ksm(xy[i],d,n);
for(ll j=1;j<=r;j++) {
y = ksc(x,x,n);
if(y==1&&x!=1&&x!=n-1) return false;
x = y;
}
if(x!=1) return false;
}
return true;
}
int main() {
ll x;
while(~scanf("%lld",&x)) {
if(miller_rabin(x)) puts("Y");
else puts("N");
}
}
快速乘(注意精度问题!)
ll ksc(ll a,ll b,ll n) {
ll tmp = a*b - ((ll)((long double)a/n*b+0.5) )*n;
return tmp<0?tmp+n:tmp;
}

浙公网安备 33010602011771号