算法竞赛模板(数论)

目录

  • 质数
    • 1e11以内质数个数
    • 快速求出n!的质因子个数
    • 线性筛质数
    • 分解质因数
      • 分解质因数优化(线性筛+分解质因数)
    • 欧拉函数
      • 求某个数的欧拉函数
      • 线性筛欧拉函数
  • 约数
    • 约数个数
      • 约数个数(优化版本)
    • 约数求和
      • 约数之和(优化版本)
  • 整数公式与整数分块
    • 整除分块
    • 整数分块
  • 分段打表
  • 高精度
    • 高精度一体化完整版
    • 高精度加法
    • 高精度减法
    • 高精度乘法
      • 高精度乘低精度
      • 高精度乘高精度
    • 高精度除法
  • 同余定理:(n+m)%p=(n%p+m%p)%p
  • 扩展欧几里得
    • 求解ax+by=gcd(a,b)
    • 求解 ax+by=c

质数

1e11以内质数个数

#include
using namespace std;
#define LL long long
const int N = 5e6 + 2;
bool np[N];
int prime[N], pi[N];
int getprime()
{
    int cnt = 0;
    np[0] = np[1] = true;
    pi[0] = pi[1] = 0;
    for(int i = 2; i < N; ++i)
    {
        if(!np[i]) prime[++cnt] = i;
        pi[i] = cnt;
        for(int j = 1; j <= cnt && i * prime[j] < N; ++j)
        {
            np[i * prime[j]] = true;
            if(i % prime[j] == 0)   break;
        }
    }
    return cnt;
}
const int M = 7;
const int PM = 2 * 3 * 5 * 7 * 11 * 13 * 17;
int phi[PM + 1][M + 1], sz[M + 1];
void init()
{
    getprime();
    sz[0] = 1;
    for(int i = 0; i <= PM; ++i)  phi[i][0] = i;
    for(int i = 1; i <= M; ++i)
    {
        sz[i] = prime[i] * sz[i - 1];
        for(int j = 1; j <= PM; ++j) phi[j][i] = phi[j][i - 1] - phi[j / prime[i]][i - 1];
    }
}
int sqrt2(LL x)
{
    LL r = (LL)sqrt(x - 0.1);
    while(r * r <= x)   ++r;
    return int(r - 1);
}
int sqrt3(LL x)
{
    LL r = (LL)cbrt(x - 0.1);
    while(r * r * r <= x)   ++r;
    return int(r - 1);
}
LL getphi(LL x, int s)
{
    if(s == 0)  return x;
    if(s <= M)  return phi[x % sz[s]][s] + (x / sz[s]) * phi[sz[s]][s];
    if(x <= prime[s]*prime[s])   return pi[x] - s + 1;
    if(x <= prime[s]*prime[s]*prime[s] && x < N)
    {
        int s2x = pi[sqrt2(x)];
        LL ans = pi[x] - (s2x + s - 2) * (s2x - s + 1) / 2;
        for(int i = s + 1; i <= s2x; ++i) ans += pi[x / prime[i]];
        return ans;
    }
    return getphi(x, s - 1) - getphi(x / prime[s], s - 1);
}
LL getpi(LL x)
{
    if(x < N)   return pi[x];
    LL ans = getphi(x, pi[sqrt3(x)]) + pi[sqrt3(x)] - 1;
    for(int i = pi[sqrt3(x)] + 1, ed = pi[sqrt2(x)]; i <= ed; ++i) ans -= getpi(x / prime[i]) - i + 1;
    return ans;
}
LL lehmer_pi(LL x)
{
    if(x < N)   return pi[x];
    int a = (int)lehmer_pi(sqrt2(sqrt2(x)));
    int b = (int)lehmer_pi(sqrt2(x));
    int c = (int)lehmer_pi(sqrt3(x));
    LL sum = getphi(x, a) +(LL)(b + a - 2) * (b - a + 1) / 2;
    for (int i = a + 1; i <= b; i++)
    {
        LL w = x / prime[i];
        sum -= lehmer_pi(w);
        if (i > c) continue;
        LL lim = lehmer_pi(sqrt2(w));
        for (int j = i; j <= lim; j++) sum -= lehmer_pi(w / prime[j]) - (j - 1);
    }
    return sum;
}
int main()
{
    init();
    LL n;
    cin>>n;
    cout<<lehmer_pi(n)<<endl;//输出n以内有多少个质数,可以输出1e11以内的
    return 0;
}

快速求出n!的质因子个数

算法竞赛模板(数论)_第1张图片

	for(int i=0;i<cnt;i++)
	{
		LL p=primes[i],a=p;
		LL s=0;
		while(p<=n)s+=n/p,p*=a;
		cout<<a<<' '<<s<<endl;
	}

线性筛质数

void get_primes(int n){
    //外层从2~n迭代,因为这毕竟算的是1~n中质数的个数,而不是某个数是不是质数的判定
    for(int i=2;i<=n;i++){
        if(!st[i]) primes[cnt++]=i;
        for(int j=0;primes[j]<=n/i;j++){//primes[j]<=n/i:变形一下得到——primes[j]*i<=n,把大于n的合数都筛了就
        //没啥意义了
            st[primes[j]*i]=true;//用最小质因子去筛合数

            //1)当i%primes[j]!=0时,说明此时遍历到的primes[j]不是i的质因子,那么只可能是此时的primes[j]
            //最小质因子,所以primes[j]*i的最小质因子就是primes[j];
            //2)当有i%primes[j]==0时,说明i的最小质因子是primes[j],因此primes[j]*i的最小质因子也就应该是
            //prime[j],之后接着用st[primes[j+1]*i]=true去筛合数时,就不是用最小质因子去更新了,因为i有最小
            //质因子primes[j]
            //退出循环,避免之后重复进行筛选。
            if(i%primes[j]==0) break;
        }
    }

}

分解质因数

void divide(int n){
    for(int i=2;i<=n/i;i++)
    {
        if(n%i==0)
        {
         //n不包含任何从2到i-1之间的质因子(已经被除干净了)
                          //(n%i==0)所以i也不包含何从2到i-1之间的质因子,由质数的定义可知,保证了i是质数
            int s=0;
            while(n%i==0) n/=i,s++;  
            cout<<i<<' '<<s<<endl;
        }
    }  
    if(n>1) cout<<n<<' '<<1<<endl;    //最多只有一个大于根下n的质因子(两个相乘就大于n了)
    cout<<endl;
}

分解质因数优化(线性筛+分解质因数)

将枚举i直接变为枚举质因子,这里用求约数个数举例

	for(int i=0;i<cnt&&primes[i]*primes[i]<=x;i++)
	{
		if(x%primes[i]==0)
		{
			int s=0;
			while(x%primes[i]==0)
			{
				s++;
				x/=primes[i];
			}
			res=res*(s+1);
		}
	}
	if(x>1)res=res*2;

欧拉函数

常用小结论:

  1. 质数的欧拉函数等于它本身-1

求某个数的欧拉函数

算法竞赛模板(数论)_第2张图片算法竞赛模板(数论)_第3张图片

int phi(int x)
{
	//公式:num=nnum*(1-1/p_1)*(1-1/p_2)....*(1-1/p_i); 
    int res=x;
    for (int i=2;i<=x/i;i++)
        if (x%i==0)//分解质因数 
        {
			while (x%i==0)x/=i;
            res=res/i*(i-1);//先除再乘防止爆long long 
            
        }
    if (x>1)res=res/x*(x-1);
    return res;
}

线性筛欧拉函数

int n;
const int N=1e6+10;
int primes[N],phi[N],cnt;//存N个质数,1~N每个数的欧拉函数 
bool st[N];//质数false,合数true
int get_eulers(int n)
{
    phi[1]=1; //1的欧拉函数只有一个,如果求小于它本身的与它互质的个数,注释此
    for(int i=2;i<=n;i++)
	{
        if(!st[i])
		{ //如果没有被筛掉
            primes[cnt++]=i;
            phi[i]=i-1; //说明这个数是质数,而质数的欧拉函数为i - 1个
        }
        for(int j=0;primes[j]<=n/i;j ++)
		{
            int t=primes[j]*i;
            st[t]=true;
            if(i%primes[j]==0)
			{ //这边上面推导过
                phi[t]=phi[i]*primes[j];
                break;
            }
            phi[t]=phi[i]*(primes[j]-1);
        }
    }
    int res=0;
    for(int i=1;i<=n;i ++)res+=phi[i]; //把所有数的欧拉函数加起来,也就是答案
    return res;
}

约数

约数个数

算法竞赛模板(数论)_第4张图片

map<int,int>mp;//i的指数
int get(int x)
{
    for(int i=2;i<=x/i;i++)
    {
        if(x%i==0)
        {
            while(x%i==0)
            {
                x/=i;
                mp[i]++;
            }
        }
    }
    if(x>1)mp[x]++;
    int res=1;
    for(auto x:mp)res=res*(x.y+1);
    return res;
}

约数个数(优化版本)

	for(int i=0;i<cnt&&primes[i]*primes[i]<=x;i++)
	{
		if(x%primes[i]==0)
		{
			int s=0;
			while(x%primes[i]==0)
			{
				s++;
				x/=primes[i];
			}
			res=res*(s+1);
		}
	}
	if(x>1)res=res*2;

约数求和

算法竞赛模板(数论)_第5张图片

#include 
using namespace std;
typedef long long LL;
const int mod=1e9+7;
int t;
int n;
unordered_map<int,int>mp;
void get(int n)
{
    for(int i=2;i<=n/i;i++)
    {
        if(n%i==0)
        {
            while(n%i==0)
            {
                mp[i]++;
                n/=i;
            }
        }
    }
    if(n>1)mp[n]++;
}
int main()
{
    cin>>t;
    while(t--)
    {
        cin>>n;
        get(n);
    }
    LL res=1;
    for(auto x:mp)
    {
        int a=x.first,b=x.second;
        LL t=1;
        while(b--)t=(t*a+1)%mod;
        res=(res*t)%mod;
    }
    cout<<res<<endl;
    return 0;
}

约数之和(优化版本)

int n;
const int N=5e4+10,mod=1e9+7;
int primes[N],phi[N],cnt;//存N个质数,1~N每个数的欧拉函数 
bool st[N];//质数false,合数true
int a[N];
int get_eulers(int n)
{
    phi[1]=1; //1的欧拉函数只有一个,如果求小于它本身的与它互质的个数,注释此
    for(int i=2;i<=n;i++)
	{
        if(!st[i])
		{ //如果没有被筛掉
            primes[cnt++]=i;
            phi[i]=i-1; //说明这个数是质数,而质数的欧拉函数为i - 1个
        }
        for(int j=0;primes[j]<=n/i;j ++)
		{
            int t=primes[j]*i;
            st[t]=true;
            if(i%primes[j]==0)
			{ //这边上面推导过
                phi[t]=phi[i]*primes[j];
                break;
            }
            phi[t]=phi[i]*(primes[j]-1);
        }
    }
}
void solve()
{
    cin>>n;
    unordered_map<int,int>mp;
    rep(i,1,n)
    {
        int x;
        cin>>x;
    	for(int i=0;i<cnt&&primes[i]*primes[i]<=x;i++)
    	{
    		if(x%primes[i]==0)
    		{
    			int s=0;
    			while(x%primes[i]==0)
    			{
    				s++;
    				x/=primes[i];
    			}
    			mp[primes[i]]+=s;
    		}
    	}
    	if(x>1)mp[x]++;
    }
	int res=1;
	for(auto x:mp)
	{
	    int sum=0;
	    int num=x.x,s=x.y;
	    rep(i,0,s)
	        sum=(sum+qmi(num,i,mod))%mod;
	    res=(res*sum)%mod;
	}

	cout<<res<<endl;
}
signed main()
{
    io;
    int _;_=1;
    get_eulers(N-1);
    //cin>>_;
    while(_--)solve();
}

整数公式与整数分块

整除分块

算法竞赛模板(数论)_第6张图片
算法竞赛模板(数论)_第7张图片
算法竞赛模板(数论)_第8张图片
算法竞赛模板(数论)_第9张图片
算法竞赛模板(数论)_第10张图片

//for(int i=start;i<=ed;i++)res+=num/i;
int block(int start,int ed,int num)
{
	int r=0;
	int res=0;
	ed=min(ed,num);
	for(int i=start;i<=ed;i=r+1)
	{
		r=min(ed,num/(num/i));
		res+=(r-i+1)*(num/i);
	}
	return res;
}

整数分块

算法竞赛模板(数论)_第11张图片

分段打表

算法竞赛模板(数论)_第12张图片
算法竞赛模板(数论)_第13张图片
算法竞赛模板(数论)_第14张图片

LL n;
int len=1010;
const int N=1e6+10;
double s[N];
int cnt;
void init(int n)
{
	double res=0;
	rep(i,1,n*len)
	{
		res+=1.0/i;
		if(i%len==0)s[i/len]+=res;
	}
}
double query(int n)
{
	int k=n/len;
	double sum=s[k];
	for(int i=k*len+1;i<=n;i++)sum+=1.0/i;
	return sum;
}

高精度

高精度一体化完整版

struct bint:vector<int>
{
    void format();
    bint(int n)
    {
        do push_back(n % 10), n /= 10; while (n);
    }
    bint(long long n)
    {
        do push_back(n % 10), n /= 10; while (n);
    }
    bint(string s)
    {
        for (int i = s.size() - 1; i >= 0; i --) push_back(s[i] - '0');
    }
    bint()
    {

    }
};
istream& operator>>(istream& in, bint& n);
ostream& operator<<(ostream& out, bint n);
bool operator<(bint a, bint b);
bool operator<=(bint a, bint b);
bool operator>(bint a, bint b);
bool operator>=(bint a, bint b);
bool operator==(bint a, bint b);
bool operator!=(bint a, bint b);
bint operator+(bint a, bint b);
bint operator-(bint a, bint b);
bint operator*(bint a, bint b);
bint operator/(bint a, bint b);
bint operator%(bint a, bint b);
template<typename T>
bint operator*(bint a, T b);
template<typename T>
bint operator/(bint a, T b);
template<typename T>
bint operator%(bint a, T b);
template<typename T>
bint operator*(T a, bint b);
bint divmode(bint& a, bint b);
template<typename T>
bint divmode(bint a, T b, T& r);
template<typename T>
void operator+=(T& a, T b);
template<typename T>
void operator-=(T& a, T b);
template<typename T>
void operator*=(T& a, T b);
template<typename T>
void operator/=(T& a, T b);
template<typename T>
void operator%=(T& a, T b);
void operator--(bint& a);
void operator++(bint& a);
void bint::format()
{
    while(size() > 1 && back() == 0) pop_back();
}
istream& operator>>(istream& in, bint& n)
{
    string s;
    in >> s;
    n.clear();
    for (int i = s.size() - 1; i >= 0; i --) n.push_back(s[i] - '0');
    return in;
}
ostream& operator<<(ostream& out, bint n)
{
    for (int i = n.size() - 1; i >= 0; i --) out << n[i];
    return out;
}
bool operator<(bint a, bint b)
{
    if (a.size() != b.size()) return a.size() < b.size();
    for (int i = a.size() - 1; i >= 0; i --)
        if (a[i] != b[i])
            return a[i] < b[i];
    return false;
}
bool operator<=(bint a, bint b)
{
    return a < b || a == b;
}
bool operator>(bint a, bint b)
{
    return !(a <= b);
}
bool operator>=(bint a, bint b)
{
    return !(a < b);
}
bool operator==(bint a, bint b)
{
    if (a.size() != b.size()) return false;
    for (int i = a.size() - 1; i >= 0; i --)
        if (a[i] != b[i])
            return false;
    return true;
}
bool operator!=(bint a, bint b)
{
    return !(a == b);
}
bint operator+(bint a, bint b)
{
    int t = 0;
    bint c;
    for (int i = 0; i < a.size() || i < b.size(); i ++)
    {
        if (i < a.size()) t += a[i];
        if (i < b.size()) t += b[i];
        c.push_back(t % 10);
        t /= 10;
    }
    if (t) c.push_back(t);
    return c;
}
bint operator-(bint a, bint b)
{
    if (b > a)
    {
        cerr << "Error occurs at BigInteger operator-(BigInteger, BigInteger)" << endl;
        cerr << "A negative result is produced" << endl;
        return a;
    }
    int t = 0;
    bint c;
    for (int i = 0; i < a.size() ; i ++)
    {
        t += a[i];
        if (i < b.size()) t -= b[i];
        if (t < 0) c.push_back(t + 10), t = -1;
        else c.push_back(t), t = 0;
    }
    c.format();
    return c;
}
bint operator*(bint a, bint b)
{
    bint c;
    c.assign(a.size() + b.size() - 1, 0);
    for(int i = 0; i < a.size(); i ++)
        for(int j = 0; j < b.size(); j ++)
            c[i + j] += a[i] * b[j];
    for (int i = 0; i < c.size() - 1; i ++)
        if (c[i] >= 10)
            c[i + 1] += c[i] / 10, c[i] %= 10;
    if (c[c.size() - 1] >= 10) c.push_back(c[c.size() - 1] / 10), c[c.size() - 2] %= 10;
    c.format();
    return c;
}
bint operator/(bint a, bint b)
{
    return divmode(a, b);
}
bint operator%(bint a, bint b)
{
    divmode(a, b);
    return a;
}
template<typename T>
bint operator*(bint a, T b)
{
    bint c;
    T t = 0;
    for (int i = 0; i < a.size() || t; i ++)
    {
        if (i < a.size()) t += a[i] * b;
        c.push_back(t % 10);
        t /= 10;
    }
    c.format();
    return c;
}
template<typename T>
bint operator*(T a, bint b)
{
    return b * a;
}
template<typename T>
bint operator/(bint a, T b)
{
    T r = 0;
    return divmode(a, b, r);
}
template<typename T>
T operator%(bint a, T b)
{
    T r;
    divmode(a, b, r);
    return r;
}
bint divmode(bint& a, bint b)
{
    if (b == 0)
    {
        cerr << "Error occurs at BigInteger operator/(BigInteger, BigInteger)" << endl;
        cerr << "Divided by zero" << endl;
        return a;
    }
    bint c, d, e;
    for (int i = a.size() - b.size(); a >= b; i --)
    {
        d.clear(), d.assign(i + 1, 0), d.back() = 1;
        int l = 0, r = 9, m;
        while (l < r)
        {
            m = l + r + 1 >> 1;
            e = b * d * m;
            if (e <= a) l = m;
            else r = m - 1;
        }
        a -= b * d * l, c += d * l;
    }
    return c;
}
template<typename T>
bint divmode(bint a, T b, T& r)
{
    bint c;
    r = 0;
    for (int i = a.size() - 1; i >= 0; i -- )
    {
        r = r * 10 + a[i];
        c.push_back(r / b);
        r %= b;
    }
    reverse(c.begin(), c.end());
    c.format();
    return c;
}
template<typename T>
void operator+=(T& a, T b)
{
    a = a + b;
}
template<typename T>
void operator-=(T& a, T b)
{
    a = a - b;
}
template<typename T>
void operator*=(T& a, T b)
{
    a = a * b;
}
template<typename T>
void operator/=(T& a, T b)
{
    a = a / b;
}
template<typename T>
void operator%=(T& a, T b)
{
    a = a % b;
}
void operator--(bint& a)
{
    a -= bint(1);
}
void operator++(bint& a)
{
    a += bint(1);
}
int main()
{
    bint a, b;
    cin >> a >> b;
    cout << a + b;
    return 0;
}

高精度加法

char str[505];

struct BigNum {
    int num[505], len;
}A, B, C;

void print(BigNum &x) { //输出大整数x 
    for(int i = x.len - 1; i >= 0; i--) printf("%d", x.num[i]);
    printf("\n");
}

void add(BigNum &x, BigNum &y, BigNum &z) {  
    z.len = max(x.len, y.len); // 结果最小长度为两者长度最大值 
    for(int i = 0; i < z.len; i++) z.num[i] = x.num[i] + y.num[i]; // 不进位加法得到初步结果 
    for(int i = 0; i < z.len; i++) 
        if(z.num[i] > 9) { // 进行逐位进位 
            z.num[i + 1] += 1;
            z.num[i] -= 10;
        }
    if(z.num[z.len]) ++z.len; // 判断最高位是否有进位 
}
int main() {
    // 读取并倒序存储大整数A 
    scanf("%s", str);
    int len = strlen(str);
    A.len = len;
    for(int i = 0; i < len; i++) A.num[len - i  - 1] = str[i] - '0';
    // 读取并倒序存储大整数B
    scanf("%s", str);
    B.len = len = strlen(str);
    for(int i = 0; i < len; i++) B.num[len - i  - 1] = str[i] - '0';
    add(A, B, C); // 计算结果 
    print(C); // 输出 
    return 0;
}

高精度减法

#define MAXN 11111
char str[MAXN];
struct BigNum {
    int num[MAXN], len;
}A, B, C;

void print(BigNum &x) { //输出大整数x 
    for(int i = x.len - 1; i >= 0; i--) printf("%d", x.num[i]);
    printf("\n");
}

int judge(BigNum &x, BigNum &y) { 
    // 比较函数  长度长的大,其次从高到低逐位比较,全相同返回0,x>y返回1, x
    if(x.len > y.len) return 1;  
    if(x.len < y.len) return -1;
    for(int i = x.len - 1; i >= 0; i--) {
        if(x.num[i] > y.num[i]) return 1;
        if(x.num[i] < y.num[i]) return -1;
    }
    return 0;
}

void Minus(BigNum &x, BigNum &y, BigNum &z) { 
    if(judge(x, y) == -1) {
        printf("-"); 
        Minus(y, x, z); //保证被减数为较大的 
    } else {    
        z.len = x.len; // 结果最小长度为x长度 
        for(int i = 0; i < z.len; i++) z.num[i] = x.num[i] - y.num[i]; // 不进位减法得到初步结果 
        for(int i = 0; i < z.len; i++) 
            if(z.num[i] < 0) { // 进行逐位退位
                z.num[i + 1] -= 1;
                z.num[i] += 10;
            }
        while(z.len > 1 && !z.num[z.len - 1]) --z.len; // 判断最高位是否有退位 
    }
    return ;
}

int main() {
    // 读取并倒序存储大整数A 
    scanf("%s", str);
    int len = strlen(str);
    A.len = len;
    for(int i = 0; i < len; i++) A.num[len - i  - 1] = str[i] - '0';
    // 读取并倒序存储大整数B
    scanf("%s", str);
    B.len = len = strlen(str);
    for(int i = 0; i < len; i++) B.num[len - i  - 1] = str[i] - '0';
    Minus(A, B, C); // 计算结果 
    print(C); // 输出 
    return 0;
}

高精度乘法

高精度乘低精度

char str[MAXN];

struct BigNum {
    int num[MAXN], len;
}A, B, C;

void print(BigNum &x) { //输出大整数x 
    for(int i = x.len - 1; i >= 0; i--) printf("%d", x.num[i]);
    printf("\n");
}

void Multi(BigNum &x, int y, BigNum &z) { 
    z.len = x.len; // 最小长度 
    for(int i = 0; i < z.len; i++) z.num[i] = x.num[i] * y; //逐位相乘 
    for(int i = 0; i < z.len; i++) { // 进位处理 
        z.num[i + 1] += z.num[i] / 10; 
        z.num[i] %= 10; 
        if(i == z.len - 1 && z.num[i + 1]) ++z.len; // 最高位进位 
    }
    return ;
}

int main() {
    // 读取并倒序存储大整数A 
    scanf("%s", str);
    int len = strlen(str);
    A.len = len;
    for(int i = 0; i < len; i++) A.num[len - i  - 1] = str[i] - '0';
    int b;
    scanf("%d", &b);
    Multi(A, b, C); // 计算结果 
    print(C); // 输出 
    return 0;
}

高精度乘高精度

#include 

#define MAXN 11111 
using namespace std;

char str[MAXN];

struct BigNum {
    int num[MAXN], len;
}A, B, C;

void print(BigNum &x) { //输出大整数x 
    for(int i = x.len - 1; i >= 0; i--) printf("%d", x.num[i]);
    printf("\n");
}

void Multi(BigNum &x, BigNum &y, BigNum &z) { 
    z.len = x.len + y.len; // 最大长度 
    for(int i = 0; i < x.len; i++)
        for(int j = 0; j < y.len; j++) // 模拟乘法竖式 
            z.num[i + j] += x.num[i] * y.num[j]; 
    for(int i = 0; i < z.len; i++) { // 进位处理 
        z.num[i + 1] += z.num[i] / 10; 
        z.num[i] %= 10; 
    }
    while(z.len > 1 && !z.num[z.len - 1]) --z.len;
    return ;
}

int main() {
    // 读取并倒序存储大整数A 
    scanf("%s", str);
    int len = strlen(str);
    A.len = len;
    for(int i = 0; i < len; i++) A.num[len - i  - 1] = str[i] - '0';
    // 读取并倒序存储大整数B
    scanf("%s", str);
    B.len = len = strlen(str);
    for(int i = 0; i < len; i++) B.num[len - i  - 1] = str[i] - '0';
    Multi(A, B, C); // 计算结果 
    print(C); // 输出 
    return 0;
}

高精度除法

#include 

#define MAXN 11111 
using namespace std;

char str[MAXN];

struct BigNum {
    int num[MAXN], len;
}A, B, C;

void print(BigNum &x) { //输出大整数x 
    for(int i = x.len - 1; i >= 0; i--) printf("%d", x.num[i]);
    printf("\n");
}

void Div(BigNum &x, int y, BigNum &z) { 
    z.len = x.len; // 初始长度 
    int t = 0;
    for(int i = z.len - 1; i >= 0; i--) {
        t = t * 10 + x.num[i]; // 当前位数字等于上一位余数乘10再加上当前位数字 
        z.num[i] = t / y; // 除法 
        t %= y; // 更新t 
    }
    while(z.len > 1 && !z.num[z.len - 1]) --z.len; //去除前导0 
    return ;
}

int main() {
    // 读取并倒序存储大整数A 
    scanf("%s", str);
    int len = strlen(str);
    A.len = len;
    for(int i = 0; i < len; i++) A.num[len - i  - 1] = str[i] - '0';
    int y;
    scanf("%d", &y);
    Div(A, y, C); // 计算结果 
    print(C); // 输出 
    return 0;
}

同余定理:(n+m)%p=(n%p+m%p)%p

扩展欧几里得

算法竞赛模板(数论)_第15张图片

求解ax+by=gcd(a,b)

int exgcd(int a,int b,int &x,int &y)
{
	if(b==0)
	{
		x=1,y=0;
		return a;
	}
	int x1,y1,g;
	g=exgcd(b,a%b,x1,y1);
	x=y1,y=x1-a/b*y1;
	return g;
}

求解 ax+by=c

求出来的d必须满足 c%d==0,否则无解
x = ( c / d ) x 0 + k ( b / d ) x=(c/d)x_0+k(b/d) x=(c/d)x0+k(b/d)
y = ( c / d ) / y 0 − k ( a / d ) y=(c/d)/y_0-k(a/d) y=(c/d)/y0k(a/d)

int exgcd(int a,int b,int &x,int &y)
{
    if(!b)
    {
        x=1;
        y=0;
        return a;
    }
    int d=exgcd(b,a%b,y,x);
    y=y-(a/b)*x;
    return d;
}

一般求一个x,所以所要求的是最小满足的x

int x=(c/d)*x0;
int k=b/d;
cout<<(x%k+k)%k<<endl;

你可能感兴趣的:(算法,数据结构,c++)