数论学习

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 100010
typedef 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 100010
typedef 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 10
typedef 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 3000010

int 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 100010

int 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 1000010

int 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 100010

int 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 10000010

int 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 20101009

int 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 0x3f3f3f3f
typedef 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 1000000009LL
typedef 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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值