PWJ的数论模板整理

一些还没学到,但已经听说的就先copy其他博客的

数论

欧拉降幂

求a1^a2^a3^a4^a5^a6 mod m

#include<cstdio>
#include<cstring>
const int N=1e4+11;
typedef long long ll;
char s[10];
int n,lens,phi[N];
ll md,a[15];
void init(){
    for(int i=1;i<N;i++) phi[i]=i;
    for(int i=2;i<N;i+=2) phi[i]/=2;
    for(int i=3;i<N;i+=2) if(phi[i]==i)
        for(int j=i;j<N;j+=i) phi[j]=phi[j]/i*(i-1);
}
ll poww(ll x,ll y,ll z){
    ll ans=1;
    if(x>=z) x=x%z+z;
    while(y){
        if(y&1){
            ans*=x;
            if(ans>=z) ans=ans%z+z;
        }
        x*=x;
        if(x>=z) x=x%z+z;
        y>>=1;
    }
    return ans;
}
ll dfs(int x,ll y){
    if(x==n-1) return a[x]>=y ? a[x]%y+y : a[x];
    if(a[x]%y==0) return 0;
    return poww(a[x],dfs(x+1,phi[y]),y);
}
int main(){
    init();
    int t=1;
    while(~scanf("%s",s)&&s[0]!=‘#‘){
        md=0;lens=strlen(s);
        for(int i=0;i<lens;i++) md=md*10+(s[i]-‘0‘);
        scanf("%d",&n);
        for(int i=0;i<n;i++) scanf("%lld",&a[i]);
        printf("Case #%d: %lld\n",t++,dfs(0,md)%md);
    }
    return 0;
}

广义斐波那契循环节

int pn,pri[100000+10];
void init(){
    ll lim;
    for(int i=2;i<=100000;i++){
        if(!pri[i]) pri[pn++]=i;
        for(int j=0;j<pn;j++){
            lim=1ll*i*pri[j];
            if(lim>100000) break;
            pri[lim]=1;
            if(i%pri[j]==0) break;
        }
    }
}
ll solve(ll x){
    ll ans1=1,ans2=1,xx=x;
    for(int i=0;i<pn;i++){
        if(1ll*pri[i]*pri[i]>x) break;
        if(x%pri[i]==0){
            ans1*=(pri[i]-1)*(pri[i]+1);
            ans2*=pri[i];
            while(x%pri[i]==0) x/=pri[i];
        }
    }
    if(x>1){
        ans1*=(x-1)*(x+1);
        ans2*=x;
    }
    return xx/ans2*ans1;
}

二次剩余

求x2Ξa(mod m)的解x

#include<cstdio>
#include<cstdlib>
#include<ctime>
struct Ima{
    int x,y;
};
int p,w;
Ima muli(const Ima &i1,const Ima &i2){
    Ima ans;
    ans.x=(i1.x*i2.x%p+i1.y*i2.y%p*w%p)%p;
    ans.y=(i1.x*i2.y%p+i1.y*i2.x%p)%p;
    return ans;
}
Ima powi(Ima a,int b){
    Ima ans;
    ans.x=1,ans.y=0;
    while(b){
        if(b&1) ans=muli(ans,a);
        a=muli(a,a);
        b>>=1;
    }
    return ans;
}
int poww(int a,int b){
    int ans=1;
    a%=p;
    while(b){
        if(b&1) ans=ans*a%p;
        a=a*a%p;
        b>>=1;
    }
    return ans;
}
int Cipolla(int n){
    if(p==2) return 1;
    if(poww(n,(p-1)>>1)+1==p) return -1;
    int a;
    while(true){
        a=rand()%p;
        w=((a*a%p-n)%p+p)%p;
        if(poww(w,(p-1)>>1)+1==p) break;
    }
    Ima ans;
    ans.x=a,ans.y=1;
    ans=powi(ans,(p+1)>>1);
    return ans.x;
}
int main(){
    int t,n,ans1,ans2;
    srand(time(NULL));
    scanf("%d",&t);
    while(t--){
        scanf("%d%d",&n,&p);
        n%=p;
        ans1=Cipolla(n),ans2=p-ans1;
        if(ans1==-1) printf("No root\n");
        else if(ans1==ans2) printf("%d\n",ans1);
        else if(ans1<ans2) printf("%d %d\n",ans1,ans2);
        else printf("%d %d\n",ans2,ans1);
    }
    return 0;
}

大素数判断

typedef unsigned long long  ll;
const int S=20;
ll mult_mod(ll a, ll b, ll c){
    a%=c;
    b%=c;
    ll ret=0,tmp=a;
    while(b){
        if(b&1){
            ret+=tmp;
            if(ret>c) ret-=c;
        }
        tmp<<=1;
        if(tmp>c) tmp-=c;
        b>>=1;
    }
    return ret;
}
ll pow_mod(ll a, ll n, ll mod){
    ll ret=1,tmp=a%mod;
    while(n){
        if(n&1)    ret=mult_mod(ret,tmp,mod);
        tmp=mult_mod(tmp,tmp,mod);
        n >>=1;
    }
    return ret;
}
bool check(ll a, ll n, ll x, ll t){
    ll ret=pow_mod(a,x,n);
    ll last=ret;
    for(int i=1;i<=t;i++){
        ret=mult_mod(ret,ret,n);
        if(ret==1&&last!=1&&last!=n-1)    return true;
        last=ret;
    }
    if(ret!=1) return true;
    else return false;
}
bool Miller_Rabin(ll n){
    if(n<2)    return false;
    if(n==2) return true;
    if((n&1)==0) return false;
    ll x=n-1,t=0;
    while((x&1)==0){
        x>>=1;
        t++;
    }
//    srand(time(NULL));
    for(int i=0;i<S;i++){
        ll a=rand()%(n-1)+1;
        if(check(a,n,x,t))    return false;
    }
    return true;
}

质因子分解

long long factor[100];//质因数分解结果(刚返回时是无序的)
int tol;//质因数的个数。数组小标从0开始

long long gcd(long long a,long long b)
{
    if(a==0)return 1;//???????
    if(a<0) return gcd(-a,b);
    while(b)
    {
        long long t=a%b;
        a=b;
        b=t;
    }
    return a;
}

long long Pollard_rho(long long x,long long c)
{
    long long i=1,k=2;
    long long x0=rand()%x;
    long long y=x0;
    while(1)
    {
        i++;
        x0=(mult_mod(x0,x0,x)+c)%x;
        long long d=gcd(y-x0,x);
        if(d!=1&&d!=x) return d;
        if(y==x0) return x;
        if(i==k){y=x0;k+=k;}
    }
}
//对n进行素因子分解
void findfac(long long n)
{
    if(Miller_Rabin(n))//素数
    {
        factor[tol++]=n;
        return;
    }
    long long p=n;
    while(p>=n)p=Pollard_rho(p,rand()%(n-1)+1);
    findfac(p);
    findfac(n/p);
}

中国剩余定理

//n个方程:x=a[i](mod m[i]) (0<=i<n)
LL china(int n, LL *a, LL *m){
    LL M = 1, ret = 0;
    for(int i = 0; i < n; i ++) M *= m[i];
    for(int i = 0; i < n; i ++){
        LL w = M / m[i];
        ret = (ret + w * inv(w, m[i]) * a[i]) % M;
    }
    return (ret + M) % M;
}

扩展中国剩余定理

typedef long long LL;
typedef pair<LL, LL> PLL;
PLL linear(LL A[], LL B[], LL M[], int n) {//求解A[i]x = B[i] (mod M[i]),总共n个线性方程组
    LL x = 0, m = 1;
    for(int i = 0; i < n; i ++) {
        LL a = A[i] * m, b = B[i] - A[i]*x, d = gcd(M[i], a);
        if(b % d != 0)  return PLL(0, -1);//答案不存在,返回-1
        LL t = b/d * inv(a/d, M[i]/d)%(M[i]/d);
        x = x + m*t;
        m *= M[i]/d;
    }
    x = (x % m + m ) % m;
    return PLL(x, m);//返回的x就是答案,m是最后的lcm值
}

java实现

import java.util.*;
import java.math.*;
public class Main {
    static BigInteger x,y;
    public static void main(String[] args){
        Scanner cin=new Scanner(System.in);
        int n=cin.nextInt();
        BigInteger m=cin.nextBigInteger();
        BigInteger x=BigInteger.ZERO,mo=BigInteger.ONE;
        BigInteger B,M,b,d,t;
        int i;
        bool flag=true;
        for(i=0;i<n;++i){
            M=cin.nextBigInteger();
            B=cin.nextBigInteger();
            b=B.subtract(x);
            d=gcd(M,mo);
            if(b.mod(d).compareTo(BigInteger.ZERO)!=0) flag=false;
            if(!flag) continue;
            t=((b.divide(d)).multiply((mo.divide(d)).modInverse(M.divide(d)))).mod(M.divide(d));
            x=x.add(mo.multiply(t));
            mo=mo.multiply(M.divide(d));
        }
        if(!flag) System.out.println("无解");
        else{
            x=((x.mod(mo)).add(mo)).mod(mo);
            System.out.println(x);
        }
    }
    static BigInteger gcd(BigInteger a,BigInteger b){
        if(b.compareTo(BigInteger.ZERO)==0)return a;
        return gcd(b,a.mod(b));
    }
}

一阶线性同余方程

通解为r+a*k r为最小非负整数解 a为lcm(a1,a2,a3...,an)

#include<cstdio>
typedef long long ll;
const int N=1e4+11;
int n;
ll aa[N],rr[N];
ll exgcd(ll a,ll b,ll &x,ll &y){
    if(!b){
        x=1;
        y=0;
        return a;
    }
    ll g=exgcd(b,a%b,y,x);
    y-=a/b*x;
    return g;
}
ll linemod(){
    ll a,b,c,r,x,y,g,k;
    a=aa[0],r=rr[0];
    for(int i=1;i<n;i++){
        b=aa[i];
        c=rr[i]-r;
        g=exgcd(a,b,x,y);
        if(c%g!=0) return -1;
        k=b/g;
        x=(x*(c/g)%k+k)%k;
        r=x*a+r;
        a=a/g*b;
    }
    return r;
}
int main(){
    while(~scanf("%d",&n)){
        for(int i=0;i<n;i++) scanf("%lld%lld",&aa[i],&rr[i]);
        printf("%lld\n",linemod());
    }
    return 0;
}

拔山盖世算法

求a^x=b(mod n)的x

#include <cstdio>
#include <cstring>
#include <cmath>
#include <map>
#include <iostream>
#include <algorithm>
using namespace std;
#define LL __int64
LL gcd(LL a,LL b)
{
    return b==0?a:gcd(b,a%b);
}
//拓展欧几里得定理,求ax+by=gcd(a,b)的一组解(x,y),d=gcd(a,b)
void gcd_mod(LL a,LL b,LL &d,LL &x,LL &y)
{
    if(!b){d=a;x=1;y=0;}
    else{gcd_mod(b,a%b,d,y,x);y-=x*(a/b);}
}
//求解模方程d*a^(x-c)=b(mod n)。d,a和n互质,无解返回-1
LL log_mod (LL a,LL b,LL n,LL c,LL d)
{
    LL m,v,e=1,i,x,y,dd;
    m=ceil(sqrt(n+0.5));     //x=i*m+j
    map<LL,LL>f;
    f[1]=m;
    for(i=1;i<m;i++)  //建哈希表,保存a^0,a^1,...,a^m-1
    {
        e=(e*a)%n;
        if(!f[e])f[e]=i;
    }
    e=(e*a)%n;//e=a^m
    for(i=0;i<m;i++)//每次增加m次方,遍历所有1<=f<=n
    {
        gcd_mod(d,n,dd,x,y);//d*x+n*y=1-->(d*x)%n=1-->d*(x*b)%n==b
        x=(x*b%n+n)%n;
        if(f[x])
        {
            LL num=f[x];
            f.clear();//需要清空,不然会爆内存
            return c+i*m+(num==m?0:num);
        }
        d=(d*e)%n;
    }

    return -1;
}
int main()
{
    LL a,b,n;
    while(scanf("%I64d%I64d%I64d",&a,&n,&b)!=EOF)
    {
        if(b>=n)
        {
            printf("Orz,I can’t find D!\n");
            continue;
        }
        if(b==0)
        {
            printf("0\n");
            continue;
        }
        LL ans=0,c=0,d=1,t;
        while((t=gcd(a,n))!=1)
        {
            if(b%t){ans=-1;break;}
            c++;
            n=n/t;
            b=b/t;
            d=d*a/t%n;
            if(d==b){ans=c;break;}//特判下是否成立。
        }
        if(ans!=0)
        {
            if(ans==-1){printf("Orz,I can’t find D!\n");}
            else printf("%I64d\n",ans);
        }
        else
        {
            ans=log_mod(a,b,n,c,d);
            if(ans==-1)printf("Orz,I can’t find D!\n");
            else printf("%I64d\n",ans);
        }
    }
    return 0;
}
/*
    求解模方程a^x=b(mod n),n不为素数。拓展Baby Step Giant Step
    模板题。

    方法:
    初始d=1,c=0,i=0;
    1.令g=gcd(a,n),若g==1则执行下一步。否则由于a^x=k*n+b;(k为某一整数),则(a/g)*a^k=k*(n/g)+b/g,(b/g为整除,若不成立则无解)
令n=n/g,d=d*a/g,b=b/g,c++则d*a^(x-c)=b(mod n),接着重复1步骤。
    2.通过1步骤后,保证了a和d都与n互质,方程转换为d*a^(x-c)=b(mod n)。由于a和n互质,所以由欧拉定理a^phi(n)==1(mod n),(a,n互质)
可知,phi(n)<=n,a^0==1(mod n),所以构成循环,且循环节不大于n。从而推出如果存在解,则必定1<=x<n。(在此基础上我们就可以用
Baby Step Giant Step方法了)
    3.令m=ceil(sqrt(n)),则m*m>=n。用哈希表存储a^0,a^1,..,a^(m-1),接着判断1~m*m-1中是否存在解。
    4.为了减少时间,所以用哈希表缩减复杂度。分成m次遍历,每次遍历a^m长度。由于a和d都与n互质,所以gcd(d,n)=1,
所以用拓展的欧几里德定理求得d*x+n*y=gcd(d,n)=1,的一组整数解(x,y)。则d*x+n*y=1-->d*x%n=(d*x+n*y)%n=1-->d*(x*b)%n=((d*x)%n*b%n)%n=b。
所以若x*b在哈希表中存在,值为k,则a^k*d=b(mod n),答案就是ans=k+c+i*m。如果不存在,则令d=d*a^m,i++后遍历下一个a^m,直到遍历a^0到a^(m-1)还未找到,则说明不解并退出。

哈希表实现

struct HashMap{//哈希表
    static const int Hash=999917,maxn=46340;
    int num,link[Hash],son[maxn+5],next[maxn+5],w[maxn+5];
    int top,Stack[maxn+5];
    void clear(){//清空表
        num=0;
        while(top)
            link[Stack[top--]]=0;
    }
    void add(int x,int y){//添加键值元素
        son[++num]=y;
        next[num]=link[x];
        w[num]=INF;
        link[x]=num;
    }
    bool count(int y){//判断表中是否有对应值
        int x=y%Hash;
        for(int j=link[x];j;j=next[j])
            if(y==son[j])
                return true;
        return false;
    }
    int &operator [](int y){//获取键的对应值
        int x=y%Hash;
        for(int j=link[x];j;j=next[j])
            if(y==son[j])
                return w[j];
        add(x,y);
        Stack[++top]=x;
        return w[num];
    }
}hashMap;
int GCD(int a,int b){
    if(b==0)
        return a;
    return GCD(b,a%b);
}
int extendedGCD(int x,int y,int &a,int &b){
    if(y==0){
        a=1;
        b=0;
        return x;
    }

    int temp;
    int gcd=extendedGCD(y,x%y,a,b);
    temp=a;
    a=b;
    b=temp-x/y*b;
    return gcd;
}

int extendBSGS(int A,int B,int C){
    //三种特判
    if(C==1){
        if(!B)
            return A!=1;
        return -1;
    }
    if(B==1){
        if(A)
            return 0;
        return -1;
    }
    if(A%C==0){
        if(!B)
            return 1;
        return -1;
    }

    int gcd=GCD(A,C);
    int D=1,num=0;
    while(gcd!=1){//把A,C变成(A,C)=1为止
        if(B%gcd)
            return -1;

        B/=gcd;//从B中约去因子
        C/=gcd;//约C中约去因子
        D=((LL)D*A/gcd)%C;//将多出的乘给D
        num++;//统计约去次数
        gcd=GCD(A,C);
    }

    int now=1;
    for(int i=0;i<=num-1;i++){//枚举0~num-1
        if(now==B)
            return i;
        now=((LL)now*A)%C;
    }

    hashMap.clear();
    int Size=ceil(sqrt(C)),Base=1;
    for(int i=0;i<=Size-1;i++){//将A^j存进哈希表
        hashMap[Base]=min(hashMap[Base],i);//存储答案最小的
        Base=((LL)Base*A)%C;
    }
    for(int i=0;i<=Size-1;i++){//扩展欧几里得求A^j
        int x,y;
        int gcd=extendedGCD(D,C,x,y);//求出x、y
        x=((LL)x*B%C+C)%C;
        if(hashMap.count(x))
            return i*Size+hashMap[x]+num;//加回num
        D=((LL)D*Base)%C;
    }
    return -1;//无解
}

int main(){
    int A,B,C;
    while(scanf("%d%d%d",&A,&B,&C)!=EOF&&(A+B+C)){
        int res=extendBSGS(A,B,C);
        if(res==-1)
            printf("No Solution\n");
        else
            printf("%d\n",res);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/LMCC1108/p/11548240.html

时间: 2024-10-01 03:08:00

PWJ的数论模板整理的相关文章

数论模板整理

1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<cstdlib> 5 #include<cmath> 6 #include<map> 7 #include<iostream> 8 using namespace std; 9 typedef long long ll; 10 #define pi acos(-1.0) 11 co

【史前巨坑】数论模板整合

跪了一下午数论 整理了一下数论模板 这是个史前巨坑,有空慢慢填 #include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #define MAXN 1000000 using namespace std; bool not_prime[MAXN]; int prime_number[MAXN]; int nu; int fac

数论代码整理

数论模板 此处均为代码,学习出门右转 一.公约数.公倍数 GCD int gcd(int x,int y){ return !y?x:gcd(y,x%y); } LCM int lcm(int x,int y){ return x/gcd(x,y)*y; } 拓展欧几里得 int x,y; int ex_gcd(int a,int b){ if(!b){ x=1,y=0;return a; } int temp=ex_gcd(b,a%b); x=y,y=temp-a/b*y; return te

数论知识整理

代码均未经过编译!!!(不用编译啦) 默认: #define ll long long 快速幂 正整数a,b,p,求a^b(mod p)的值,时间复杂度O(logb) ll ksm(ll a, ll b, ll p) { ll c = 1 % p; a %= p; while (b) { if (b & 1) c = c * a % p; a = a * a % p; b >>= 1; } return c; } 最大公约数 正整数a,b,求a,b的最大公约数,时间复杂度在log级别

手机客户端接口开发文档模板整理

这是个人整理的手机开发文档模板,方便自己以后编写文档. 大体内容如下,详细在个人csdn中下载: 移动端转发短信上传温湿度信息 移动端负责后台接收温湿度传感器通过短信发来的温湿度和经纬度信息,移动端后台接收后上传web服务器,当然传感器也可通过wifi直接上传web服务器.返回小写true或者false. 请求URL: http://192.168.1.101:8080/RFID/addTransTemperature.action?phoneNumber=123&temperature=12.

[信息学]省选前模板整理

省选前把板子整理一遍,如果发现有脑抽写错的情况,欢迎各位神犇打脸 :) 数学知识 数论: //组合数 //C(n,m) 在n个数中选m个的方案数 ll C[N][N]; void get_C(int n) { for(int i=1;i<=n;i++) { C[i][i]=C[i][0]=1; for(int j=1;j<i;j++) C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod; } } //欧几里得算法 //(a,b) ll gcd(ll a,ll b) { re

『嗨威说』常见的C++函数模板整理(一)

开学两天,身上的职责直接变为两个班班长,三个小组组长,哇这事情估计够我忙活了,想躲都躲不掉啊,看来我还是真招人推荐各种管理职务啊,以后要是有人推荐我当经理啊领导啊该多好哈哈哈哈.记得今天奶奶生日,很开心地给奶奶打了一通电话,这怕是我第一次给奶奶电话送生日祝福了哈哈哈,是啊,很想珍惜身边的人,但很多时候却一心想提高自己地能力而忽视了身边人,就这四年,就这四年好好提升自己,毕业出来一定要好好陪陪家里祖辈亲戚们. 今天有点特殊,我整理了一下学到这么久编程以来的一些模板和技巧,虽然还没整理完,就作为(一

ACM模板整理|2019/12/27

看到群里都是18.19级的学弟,才发现自己老了啊?? 还算充实的一天,就是电影还没看.. 最短路 Floyd 应用 1.Floyd求有向图最小环:枚举g[i][i] 2.Floyd求无向图最小环: if (f[k][i] && f[k][j] ) { ans = min(e[i][j]+2,ans); } const int inf = 0x3f3f3f3f; int g[MAX_N][MAX_N]; // 算法中的 G 矩阵 // 首先要初始化 g 矩阵 void init() { fo

【POJ 3241】曼哈顿最小生成树(模板整理)

关于 曼哈顿最小生成树 的证明见:http://www.2cto.com/kf/201505/399861.html 模板: #include<cmath> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int MAXN = 100010; const int INF = 0x3f3f3f3f; struct Point{ int x,y,i