数论学习

来源:互联网 发布:手机一键还原软件 编辑:程序博客网 时间:2024/05/19 09:39

1⃣️扩展欧几里得算法

sgu 141 扩展欧几里德+枚举大法,不过sgu好像崩了。。。。


poj 2891

合并模方程式

#include <cstdio>#include <iostream>#include <algorithm>#include <cstring>#include <cmath>#include <queue>#include <vector>using namespace std;#define N 100010typedef long long ll;ll K;ll a[N],r[N];inline ll read(){    ll x=0,f=1;char ch=getchar();    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}    while(ch<='9'&&ch>='0'){x=x*10+ch-'0';ch=getchar();}    return x*f;}void Exgcd(ll a,ll b,ll &x,ll &y,ll &d){    if(b==0)    {        d=a;x=1;y=0;        return;    }    Exgcd(b,a%b,y,x,d);    y-=a/b*x;}ll work(){    ll Last_a=a[1],Last_r=r[1],x,y,d;    for(int i=2;i<=K;i++)    {        Exgcd(Last_a,a[i],x,y,d);        if((r[i]-Last_r)%d!=0)            return -1;        ll tmp=a[i]/d;        x=((r[i]-Last_r)/d*x)%tmp;        Last_r+=x*Last_a;        Last_a=Last_a/d*a[i];        Last_r%=Last_a;    }    return Last_r>0?Last_r:Last_r+Last_a;}int main(){    while(scanf("%lld",&K)!=EOF)    {        for(ll i=1;i<=K;i++)        {            a[i]=read();r[i]=read();        }        printf("%lld\n",work());    }    return 0;}


2⃣️Miller-Rabbin 素数检测法

1.费马小定理

2.二次探测定理

#include <cstdio>#include <iostream>#include <algorithm>#include <cstring>#include <cmath>#include <queue>#include <vector>using namespace std;typedef long long ll;const int S=3;int K,Ans;ll A[4]={0,2,7,61};     //黑科技一波inline ll read(){    int x=0,f=1;char ch=getchar();    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}    while(ch<='9'&&ch>='0'){x=x*10+ch-'0';ch=getchar();}    return x*f;}ll Quick_mul(ll a,ll b,ll n){    ll base=a,r=0;    while(b)    {        if(b&1)            r=(r+base)%n;        base=(base+base)%n;        b>>=1;    }    return r;}ll Quick_pow(ll a,ll exp,ll n){    ll base=a,r=1;    while(exp)    {        if(exp&1)            r=r*base%n;        base=base*base%n;        exp>>=1;    }    return r;}bool Miller_Rabbin(ll n){    if(n==2)return true;    int t=0;    ll a,x,y,u=n-1;    while(!(u&1))    {        t++;u>>=1;    }    for(int i=1;i<=S;i++)    {        a=A[i];        x=Quick_pow(a,u,n);        for(int j=1;j<=t;j++)        {            y=Quick_mul(x,x,n);            if(y==1&&x!=1&&x!=n-1)                return false;            x=y;        }        if(x!=1)            return false;    }    return true;}int main(){    while(scanf("%d",&K)!=EOF)    {        Ans=0;        for(int i=1;i<=K;i++)        {            ll n=read();            if(Miller_Rabbin(n))                Ans++;        }        printf("%d\n",Ans);    }    return 0;}


3⃣️.快速求逆元

4⃣️卢卡斯定理  ---组合数取模

Lucas(n,m,p)=c(n%p,m%p)*Lucas(n/p,m/p,p)


1.hdu 3037 Saving Beans

#include <cstdio>#include <iostream>#include <algorithm>#include <cstring>#include <cmath>#include <queue>#include <vector>using namespace std;#define N 100010typedef long long ll;int T;ll n,m,p;ll pre[N],S_pre[N];ll Quick_mul(ll a,ll b){    ll base=a,r=0;    while(b)    {        if(b&1)            r=(r+base)%p;        base=(base+base)%p;        b>>=1;    }    return r;}ll Quick_pow(ll a,ll exp){    ll base=a,r=1;    while(exp)    {        if(exp&1)            r=Quick_mul(r,base);        base=Quick_mul(base,base);        exp>>=1;    }    return r;}void Prepare(){    pre[0]=1;    for(int i=1;i<=p;i++)        pre[i]=pre[i-1]*i%p;    S_pre[p-1]=Quick_pow(pre[p-1],p-2);    for(int i=(int)p-2;i>=1;i--)        S_pre[i]=S_pre[i+1]*(i+1)%p;    S_pre[0]=1;}int main(){    scanf("%d",&T);    while(T--)    {        scanf("%lld%lld%lld",&n,&m,&p);        n+=m;        Prepare();        ll Ans=1;        while(n||m)        {            ll t1=n%p,t2=m%p;            if(t1<t2)            {                Ans=0;break;            }            ll tmp=((pre[t1]*S_pre[t1-t2])%p*S_pre[t2])%p;            Ans=Ans*tmp%p;            n/=p;m/=p;        }        printf("%lld\n",Ans);    }    return 0;}


5⃣️.中国剩余定理

网上看了好多都是在乱扯。。。强行把欧几里德题解说成中国剩余定理 如上poj 2891


1.hdu 1370  Biorhythms

#include <cstdio>#include <iostream>#include <algorithm>#include <cstring>#include <cmath>#include <queue>#include <vector>using namespace std;#define N 10typedef long long ll;ll A[N],B[N],C[N];inline ll read(){    ll x=0,f=1;char ch=getchar();    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}    while(ch<='9'&&ch>='0'){x=x*10+ch-'0';ch=getchar();}    return x*f;}void Exgcd(ll a,ll b,ll &x,ll &y,ll &d){    if(b==0)    {        d=a;x=1;y=0;        return;    }    Exgcd(b,a%b,y,x,d);    y-=a/b*x;}int main(){    ll Zy=read();    ll Lim_min,x,y,d;    ll Mul=23*28*33;    Exgcd(Mul/23,23,x,y,d);B[1]=x;C[1]=23;    Exgcd(Mul/28,28,x,y,d);B[2]=x;C[2]=28;    Exgcd(Mul/33,33,x,y,d);B[3]=x;C[3]=33;    int Case=0;    while(scanf("%lld%lld%lld%lld",&A[1],&A[2],&A[3],&Lim_min))    {        if(A[1]==-1&&A[2]==-1&&A[3]==-1&&Lim_min==-1)            break;        ll Ans=0;        for(int i=1;i<=3;i++)        {            Ans=(Ans+Mul/C[i]*B[i]*A[i])%Mul;        }        if(Ans<=Lim_min)        {            ll qwer=(Lim_min-Ans)/Mul+1;            Ans+=qwer*Mul;        }        printf("Case %d: the next triple peak occurs in %lld days.\n",++Case,Ans-Lim_min);    }    return 0;}


6⃣️欧拉函数与莫比乌斯函数


1.hdu 2824 (线性筛求欧拉函数)

#include <cstdio>#include <iostream>#include <algorithm>#include <cstring>#include <cmath>#include <queue>#include <vector>using namespace std;#define N 3000010int a,b,tot;int phi[N],Prime[N/3];bool flag[N];void Prepare(){    for(int i=2;i<=3000000;i++)    {        if(!flag[i])        {            Prime[++tot]=i;            phi[i]=i-1;        }        for(int j=1;(long long)Prime[j]*i<=3000000;j++)        {            flag[i*Prime[j]]=1;            if(i%Prime[j]==0)            {                phi[i*Prime[j]]=phi[i]*Prime[j];                break;            }            else                phi[i*Prime[j]]=phi[i]*(Prime[j]-1);        }    }}int main(){    Prepare();    while(scanf("%d%d",&a,&b)!=EOF)    {        long long Ans=0;        for(int i=a;i<=b;i++)            Ans+=phi[i];        printf("%lld\n",Ans);    }    return 0;}


2.求 ∑gcd(i,j)      1≤i≤n ,   1≤j≤m

Orz KZF


其过程就是不断替换求和公式的变量得到新的求和公式(瞎bb的)

#include <cstdio>#include <iostream>#include <algorithm>#include <cstring>#include <cmath>#include <queue>#include <vector>using namespace std;#define N 100010int n,m,tot;int Prime[N],phi[N];bool flag[N];void Prepare(){    phi[1]=1;    for(int i=2;i<=100000;i++)    {        if(!flag[i])        {            Prime[++tot]=i;            phi[i]=i-1;        }        for(int j=1;(long long)Prime[j]*i<=100000;j++)        {            flag[i*Prime[j]]=true;            if(i%Prime[j]==0)            {                phi[i*Prime[j]]=phi[i]*Prime[j];                break;            }            else                phi[i*Prime[j]]=phi[i]*(Prime[j]-1);        }    }}int main(){    Prepare();    int a,b;scanf("%d%d",&a,&b);    n=min(a,b);m=max(a,b);    long long Ans=0;    for(int i=1;i<=n;i++)    {        Ans+=(long long)(n/i)*(m/i)*phi[i];    }    cout<<Ans<<endl;    return 0;}

那么如果n是10^9数量级的呢?

让我们继续orz


复杂度s

O(n^0.67)


3.poj 2480 (被网上坑了。。。看了好久。。暴力不就行了么,推个毛公式啊)

#include <cstdio>#include <iostream>#include <algorithm>#include <cstring>#include <cmath>#include <queue>#include <vector>using namespace std;#define N 1000010int n,tot;int Prime[N];bool flag[N];void Prepare(){    for(int i=2;i<=1000000;i++)    {        if(!flag[i])        {            Prime[++tot]=i;        }        for(int j=1;(long long)Prime[j]*i<=1000000;j++)        {            flag[i*Prime[j]]=true;            if(i%Prime[j]==0)                break;        }    }}int Get_phi(int k){    if(k==1)return 1;    int num=k;    for(int i=1;i<=tot;i++)    {        if(k%Prime[i]==0)        {            num=num/Prime[i]*(Prime[i]-1);            while(k%Prime[i]==0)                k/=Prime[i];            if(k==1)                break;        }    }    if(k!=1)        num=num/k*(k-1);    return num;}int main(){    Prepare();    while(scanf("%d",&n)!=EOF)    {        long long Ans=0;        for(int i=1;i<=sqrt((double)n);i++)        {            if(n%i==0)            {                Ans+=(long long)i*Get_phi(n/i);                if(i!=(n/i))                {                    int t=n/i;                    Ans+=(long long)t*Get_phi(i);                }            }        }        printf("%lld\n",Ans);    }    return 0;}


4.NYOJ 1066 CO—PRIME  

莫比乌斯反演

此题中,设F(d)表示n个数中gcdd的倍数的数有多少对,f(d)表示n个数中gcd恰好为d的数有多少对,

F(d)=f(n) (n % d == 0)

f(d)=mu[n / d] * F(n) (n %d == 0)   

--------->  f(1)=mu[n] * F(n)   

                                         .......(摘抄From   http://blog.csdn.net/lyhvoyage/article/details/38455415)




#include <cstdio>#include <iostream>#include <algorithm>#include <cstring>#include <cmath>#include <queue>#include <vector>using namespace std;#define N 100010int n,tot,Max;int A[N],Prime[N],mu[N],num[N],cnt[N];bool flag[N];inline int read(){    int x=0,f=1;char ch=getchar();    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}    while(ch<='9'&&ch>='0'){x=x*10+ch-'0';ch=getchar();}    return x*f;}void Prepare(){    mu[1]=1;    for(int i=2;i<=100000;i++)    {        if(!flag[i])        {            Prime[++tot]=i;            mu[i]=-1;        }        for(int j=1;(long long)i*Prime[j]<=100000;j++)        {            flag[i*Prime[j]]=true;            if(i%Prime[j]==0)            {                mu[i*Prime[j]]=0;                break;            }            else                mu[i*Prime[j]]=mu[i]*(-1);        }    }}int main(){    Prepare();    while(scanf("%d",&n)!=EOF)    {        Max=0;        memset(num,0,sizeof(num));        memset(cnt,0,sizeof(cnt));        for(int i=1;i<=n;i++)        {            A[i]=read();            Max=max(Max,A[i]);num[A[i]]++;        }        for(int i=1;i<=Max;i++)        {            for(int j=i;j<=Max;j+=i)                cnt[i]+=num[j];        }        long long Ans=0;        for(int i=1;i<=Max;i++)        {            Ans+=(long long)mu[i]*cnt[i]*(cnt[i]-1)/2;        }        printf("%lld\n",Ans);    }    return 0;}


5.bzoj 2820 YY的GCD

莫比乌斯函数

orz Hzwer.......


在维护一个前缀和做。。。。。

#include <cstdio>#include <iostream>#include <algorithm>#include <cstring>#include <cmath>#include <queue>#include <vector>using namespace std;#define N 10000010int n,m,tot,Max;int A[N],Prime[N],mu[N],num[N],cnt[N],F[N];long long sum[N];bool flag[N];inline int read(){    int x=0,f=1;char ch=getchar();    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}    while(ch<='9'&&ch>='0'){x=x*10+ch-'0';ch=getchar();}    return x*f;}void Prepare(){    mu[1]=1;    for(int i=2;i<=10000000;i++)    {        if(!flag[i])        {            Prime[++tot]=i;            mu[i]=-1;        }        for(int j=1;(long long)i*Prime[j]<=10000000;j++)        {            flag[i*Prime[j]]=true;            if(i%Prime[j]==0)            {                mu[i*Prime[j]]=0;                break;            }            else                mu[i*Prime[j]]=mu[i]*(-1);        }    }    for(int i=1;i<=tot;i++)    {        for(int j=Prime[i];j<=10000000;j+=Prime[i])            F[j]+=mu[j/Prime[i]];    }    for(int i=1;i<=10000000;i++)        sum[i]=sum[i-1]+F[i];}int main(){    Prepare();    int T=read();    while(T--)    {        n=read();m=read();        if(n>m)swap(n,m);        long long Ans=0;        for(int i=1,j;i<=n;i=j+1)     //这段666        {            j=min(n/(n/i),m/(m/i));            Ans+=(sum[j]-sum[i-1])*(n/i)*(m/i);        }        printf("%lld\n",Ans);    }    return 0;}

6.bzoj 2154 Crash的数字表格


#include <cstdio>#include <iostream>#include <algorithm>#include <cstring>#include <cmath>#include <queue>#include <vector>using namespace std;#define N 10000010#define Mod 20101009int n,m,tot;int Prime[N/3],F[N],mu[N];int sum[N];bool flag[N];long long Ans;void Prepare(int n){    mu[1]=1;    for(int i=2;i<=n;i++)    {        if(!flag[i])        {            Prime[++tot]=i;            mu[i]=-1;F[i]=-i;        }        for(int j=1;(long long)i*Prime[j]<=n;j++)        {            flag[i*Prime[j]]=true;            if(i%Prime[j]==0)            {                mu[i*Prime[j]]=0;                break;            }            mu[i*Prime[j]]=mu[i]*(-1);        }    }    for(int i=1;i<=n;i++)        sum[i]=(sum[i-1]+((long long)i*i%Mod*mu[i]))%Mod;}long long Cal(int x,int y){    long long t1=(long long)(x+1)*x/2%Mod,t2=(long long)(y+1)*y/2;    return t1*(t2%Mod)%Mod;}int Get(int x,int y){    long long Sum=0;    for(int i=1,j;i<=x;i=j+1)    {        j=min(x/(x/i),y/(y/i));        long long qwer=Cal(x/i,y/i)*(sum[j]-sum[i-1])%Mod;        Sum=(Sum+qwer)%Mod;    }    return (int)Sum;}int main(){    cin>>n>>m;    if(n>m)swap(n,m);    Prepare(m);    for(int i=1,j;i<=n;i=j+1)    {        j=min(n/(n/i),m/(m/i));        long long qwer=(long long)(i+j)*(j-i+1)/2%Mod*Get(n/i,m/i)%Mod;        Ans=(Ans+qwer)%Mod;    }    Ans=(Ans+Mod)%Mod;    cout<<Ans<<endl;    return 0;}


7⃣️扩展大步小步算法

bzoj 2480 Mod

真是醉了,写了个快速乘比普通的还慢。。tle了找了好久

/**************************************************************    Problem: 2480    User: Edward2173    Language: C++    Result: Accepted    Time:6368 ms    Memory:2604 kb****************************************************************/ #include <cstdio>#include <iostream>#include <algorithm>#include <cstring>#include <cmath>#include <map>#include <queue>#include <vector>using namespace std; #define N 100010#define INF 0x3f3f3f3ftypedef long long ll; int a,b,p;int len[N]; int GCD(int a,int b){    return !b?a:GCD(b,a%b);} ll Quick_mul(ll a,ll b){    ll base=a,r=0;    while(b)    {        if(b&1)            r=(r+base)%p;        base=(base+base)%p;        b>>=1;    }    return r;} ll Quick_pow(int a,int exp){    ll base=a,r=1;    while(exp)    {        if(exp&1)            r=r*base%p;        base=base*base%p;        exp>>=1;    }    return r;} int work(int a,int b){    a%=p;b%=p;    if(!b)return 0;    ll Add=0,tmp=1;    while(1)    {        int qwer=GCD(a,p);        if(b%qwer!=0)            return INF;        if(qwer==1)            break;        tmp=tmp*a/qwer%p;        b/=qwer;p/=qwer;        Add++;        if(tmp==b)            return (int)Add;    }    map<ll,int> Hash;    int Unit=sqrt((double)p+1.0),Ans=INF;    ll now=b;Hash[now]=0;    for(int i=1;i<Unit;i++)    {        now=now*a%p;        Hash[now]=i;    }    ll base=Quick_pow(a,Unit),S_now=tmp;    for(int i=1;i<=Unit+1;i++)    {        S_now=S_now*base%p;        if(Hash.count(S_now))            return i*Unit-Hash[S_now]+(int)Add;    }    return Ans;} int main(){    while(scanf("%d%d%d",&a,&p,&b))    {        if(a==0&&b==0&&p==0)            break;        int qwer=work(a,b);        if(qwer==INF)            printf("No Solution\n");        else printf("%d\n",qwer);    }    return 0;}


8⃣️斐波那契数列

codeforces 446 C   推下公式就行了

#include <cstdio>#include <iostream>#include <algorithm>#include <cstring>#include <cmath>#include <queue>#include <vector>using namespace std;#define N 300010#define Mod 1000000009LLtypedef long long ll;int n,m;ll f[N],F[N],G[N],A[N];ll a[N*4],b[N*4],sum[N*4];inline int read(){    int x=0,f=1;char ch=getchar();    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}    while(ch<='9'&&ch>='0'){x=x*10+ch-'0';ch=getchar();}    return x*f;}void Prepare(){    G[1]=f[1]=F[0]=F[1]=1;    for(int i=2;i<=300000;i++)    {        f[i]=(f[i-1]+f[i-2])%Mod;        F[i]=(F[i-1]+f[i-1])%Mod;        G[i]=(G[i-1]+f[i])%Mod;    }}void Pushup(int i){    sum[i]=(sum[i*2]+sum[i*2+1])%Mod;}void Change(int i,int len,ll v1,ll v2){    a[i]=(a[i]+v1)%Mod;    b[i]=(b[i]+v2)%Mod;    sum[i]=(sum[i]+F[len-1]*v1%Mod+G[len-1]*v2%Mod)%Mod;}void Pushdown(int i,int l,int r){    if(a[i]==0&&b[i]==0)        return;    int mid=(l+r)/2,len=mid-l+1;    Change(i*2,len,a[i],b[i]);    ll v1=(f[len-1]*a[i]+f[len]*b[i])%Mod,v2=(f[len]*a[i]+f[len+1]*b[i])%Mod;    Change(i*2+1,r-mid,v1,v2);    a[i]=b[i]=0;}void Build(int i,int l,int r){    if(l==r)    {        a[i]=b[i]=0;sum[i]=A[l];        return;    }    int mid=(l+r)/2;    Build(i*2,l,mid);    Build(i*2+1,mid+1,r);    Pushup(i);}void Update(int i,int l,int r,int left,int right,ll v1,ll v2){    if(l>=left&&r<=right)    {        Change(i,r-l+1,v1,v2);        return;    }    Pushdown(i,l,r);    int mid=(l+r)/2;    if(left<=mid)        Update(i*2,l,mid,left,right,v1,v2);    if(right>mid)    {        ll t1=v1,t2=v2;        if(left<=mid)        {            int len=mid-max(left,l)+1;            t1=(f[len-1]*v1+f[len]*v2)%Mod;            t2=(f[len]*v1+f[len+1]*v2)%Mod;        }        Update(i*2+1,mid+1,r,left,right,t1,t2);    }    Pushup(i);}ll Query(int i,int l,int r,int left,int right){    if(l>=left&&r<=right)    {        return sum[i];    }    Pushdown(i,l,r);    int mid=(l+r)/2;    if(right<=mid)        return Query(i*2,l,mid,left,right);    else if(left>mid)        return Query(i*2+1,mid+1,r,left,right);    else        return (Query(i*2,l,mid,left,mid)+Query(i*2+1,mid+1,r,mid+1,right))%Mod;}int main(){    Prepare();    n=read();m=read();    for(int i=1;i<=n;i++)        A[i]=read();    Build(1,1,n);    for(int i=1;i<=m;i++)    {        int kind=read(),x=read(),y=read();        if(kind==1)            Update(1,1,n,x,y,1,1);        else            printf("%lld\n",Query(1,1,n,x,y));    }    return 0;}




暂时更到这儿了,以后再继续。。。    2016.1.23

2 0