【复习】幼儿园数论复习

害怕

扩欧

因为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;
}
 
posted @ 2018-07-28 13:28  Newuser233  阅读(8)  评论(0)    收藏  举报