数论基础2

文章修改不会置顶看着真难受…

⑤miller-rabin

记n-1=a*2^b。在[1,n)中随机选取一个整数x,如果x^a≡1或x^(a*2^i)≡-1(其中0<=i<b),那么我们认为n是质数。

正确率大概是((1/4)^随机次数)

⑥pollard-rho

一个比较看脸的算法…

我们先定义一个函数f(x)=(x^2+1)%n。那么如果我一直调用f(x),f(f(x)),f(f(f(x)))…那么就可以生成一个随机数数列对吧。

pollard_rho是一个可以接受一个数n,返回它的一个因数的算法。算法流程是这样的,开始有一个x[1],在[0,n)里面随机的,我们令x[i]=f(x[i-1])。

我们每次计算gcd(x[k]-x[2k],n),如果返回n就说明分解失败,需要重新生成一个x[1]。如果返回1就继续把k加1。否则的话我们就找到了n的一个因数。

实现的时候需要注意因为这个随机函数f的一些性质,当n为2的倍数时最好特判掉,否则似乎可能会死循环。

我们来算算复杂度,这个复杂度看起来比较玄学,它可以在O(sqrt(p))的时间复杂度内找到n的一个小因子p,所以复杂度差不多是O()的(因为还有一个gcd和快速乘(算f的时候由于数据范围的问题一般都会用))。

那如果要拿来分解质因数,复杂度差不多是O()的…事实上还要写miller-rabin啊,快速乘啊,内存分配啊,常数非常之大…

例4 因数和

给一个比较大的数n,求n的所有因数的和。有多组数据。

t<=50,n<=10^18。

这就是一道pollard-rho裸题。你觉得pollard-rho要跑多久?0.1s?

就是这样,所以pollard-rho的常数平常还是要注意一下…

这份代码用了vector,但是质因子数量不会超过60个,存下来应该没什么太大问题

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <algorithm>
#include <string.h>
#include <vector>
#include <math.h>
#include <limits>
#include <set>
#include <map>
using namespace std;
typedef long long ll;
ll c_f(ll a,ll b,ll c)
{
    if(b==0) return 0;
    ll hf=c_f(a,b>>1,c);
    hf=(hf+hf)%c;
    if(b&1) hf=(hf+a)%c;
    return hf;
}
ll cf(ll a,ll b,ll c)
{
    a%=c; b%=c;
    if(!a||!b) return 0;
    if(a<0&&b<0) a=-a,b=-b;
    if(b<0) return c-c_f(a,-b,c);
    if(a<0) return c-c_f(-a,b,c);
    return c_f(a,b,c);
}
ll qp(ll x,ll y,ll m)
{
    if(y==0) return 1;
    ll hf=qp(x,y>>1,m);
    hf=cf(hf,hf,m);
    if(y&1) hf=cf(hf,x%m,m);
    return hf;
}
bool isprime(ll p)
{
    int b=0; ll a=p-1;
    while(!(a&1)) ++b, a>>=1;
    for(int i=1;i<=10;i++)
    {
        ll x=rand()%(p-1)+1;
        if(qp(x,a,p)==1) goto ct;
        for(int j=0;j<b;j++)
        {
            if(qp(x,a*(1<<j),p)==p-1) goto ct;
        }
        return 0;
        ct:;
    }
    return 1;
}
ll f(ll x,ll p) {return (cf(x%p,x%p,p)+1)%p;}
ll gcd(ll a,ll b)
{
    if(a<0) a=-a;
    if(b<0) b=-b;
    while(b) {ll g=a%b; a=b; b=g;}
    return a;
}
ll pollard_rho(ll m)
{
    if(m==1) return 1;
    if(m%2==0) return 2;
    if(m%3==0) return 3;
    if(isprime(m)) return m;
    s:
    ll x=rand()%m,y=f(x,m),p=1;
    while(p==1)
    {
        x=f(x,m);
        y=f(f(y,m),m);
        p=gcd(x-y,m);
    }
    if(p==m) goto s;
    return p;
}
#define vll vector<ll>
vll merge(vll a,vll b)
{
    vll ans;
    int as=0,bs=0;
    while(as<a.size()) ans.push_back(a[as++]);
    while(bs<b.size()) ans.push_back(b[bs++]);
    return ans;
}
vll ysh(ll x)
{
    if(x==1) {return vll();}
    if(isprime(x)) {vll ans; ans.push_back(x); return ans;}
    ll ys; vll ans;
    while((ys=pollard_rho(x))!=1)
    {
        vll cur=ysh(ys);
        while(x%ys==0) x/=ys, ans=merge(ans,cur);
    }
    return ans;
}
ll calc(vll x)
{
    sort(x.begin(),x.end());
    int n=x.size();
    ll ss=1;
    for(int i=0;i<n;i++)
    {
        ll cur=x[i];
        int tot;
        for(int j=i;j<n;j++)
        {
            if(x[j]!=cur) break;
            tot=j;
        }
        int cnt=tot-i+1;
        ll sum=1,sp=1;
        for(int i=1;i<=cnt;i++) sp=sp*cur, sum+=sp;
        ss*=sum;
        i=tot;
    }
    return ss;
}
int main()
{
    int T; ll x;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%lld",&x);
        printf("%lld\n",calc(ysh(x)));
    }
}

⑦中国剩余定理

正常版本:

给n个质数/互质的数,给你一个x除以这些数得到的余数,求最小的x。

比如求一个x使得x mod 3=2,x mod 5=3,x mod 7=5。

我们先求是5、7的倍数且mod 3=2的x,即35p mod 3=2,这个exgcd解一解。然后求是3、7倍数且mod 5=3的,然后是5、7倍数且mod 3=2的,然后加在一起就可以得到满足条件的了。

然后ysy给了一个神奇的公式:

似乎正确性显然。

特殊版本?

例5 解方程组

给出n个方程,每个方程形如x mod pi=ai,求最小的满足条件的非负整数x。无解输出-1。

n<=6,pi<=1000(其实就是告诉你答案不会爆long long

我们发现互质的条件不见了,而且还有可能出现相矛盾的情况…

例如x mod 4=2,x mod 2=1就是相矛盾的。

嗯我们似乎只要把每个pi拆分成素数的幂然后就可以转化为普通版本了。

好写吗? (╯‵□′)╯︵┻━┻ 难写得不行好吗

靠谱一点的做法呢?

我们可以把这些方程合并在一起!

假设我们要合并x mod b1=n1,x mod b2=n2。

设x=b1*k1+n1=b2*k2+n2,那么b1*k1-b2*k2=n2-n1。

我们可以用exgcd解出k1(注意判无解的情况),然后带回得到x=X‘,然后我们就可以把两个方程合并为x mod lcm(b1,b2)=X‘。

开始令x mod 1=0即可。

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <algorithm>
#include <string.h>
#include <vector>
#include <math.h>
#include <limits>
#include <set>
#include <map>
using namespace std;
typedef long long ll;
int n;
ll gcd(ll a,ll b)
{
    if(a<0) a=-a;
    if(b<0) b=-b;
    while(b) {ll t=a%b; a=b; b=t;}
    return a;
}
void ex_gcd(ll a,ll b,ll& x,ll& y)
{
    if(!b) {x=1; y=0; return;}
    ex_gcd(b,a%b,x,y);
    ll y_=x-a/b*y; x=y; y=y_;
}
ll exgcd(ll a,ll b,ll c)
{
    ll gg=gcd(a,b);
    if(c%gg) return -2333;
    a/=gg; b/=gg; c/=gg;
    ll x,y;
    ex_gcd(a,b,x,y);
    x=x*c; x%=b; y=(c-x*a)/b;
    return x;
}
ll lcm(ll a,ll b) {return a/gcd(a,b)*b;}
int main()
{
    ll x=1,y=0,g,h;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%lld%lld",&g,&h);
        long long p=exgcd(x,g,h-y);
        if(p==-2333) {puts("-1"); return 0;}
        long long X=p*x+y;
        long long lc=lcm(x,g);
        y=(X%lc+lc)%lc; x=lc;
    }
    printf("%lld\n",y);
}
时间: 2024-10-08 00:35:44

数论基础2的相关文章

数论基础的补充讲解

数论基础的补充讲解 整除的一些性质: (1)能被2整除的数,个位上的数都能被2整除 (2*)能被4整除的数,个位和十位所组成的两位数能被4整除 (3*)能被8整除的数,百位.十位和个位所组成的三位数能被8整除 (4)能被5整除的数,末尾是0或5 (5*)能被25整除的数,十位和个位所组成的两位数能被25整除 (6*)能被125整除的数,百位.十位和个位所组成的三位数能被125整除 (7)能被3整除的数,各个数位上的数字之和能被3整除 (8*)能被9整除的数,各个数位上的数字和能被 9 整除 (9

数论基础题目八题【欧几里得】【筛法素数】【中国剩余定理】

之前看的数论的知识,现在做几道题目找找感觉..... poj 1061 传送门 题目大意,给你x,y,m,n,L.代表青蛙a的坐标x,青蛙b的坐标y,青蛙a一次跳的距离m,青蛙b一次跳的距离n,以及mod的值L,求经过多少次跳相遇.即求:(m-n)*x0=(x-y)(mod L);  模线性方程的解,不过要注意处理,因为(m-n)和(x-y)有可能是负的,如果(m-n)是负的,则直接对俩数取负数,下面就是对 ((x-y)+L)%L. 然后就能用modular_linear_equation(LL

数论基础的补充解说

数论基础的补充解说 整除的一些性质: (1)能被2整除的数,个位上的数都能被2整除 (2*)能被4整除的数,个位和十位所组成的两位数能被4整除 (3*)能被8整除的数,百位.十位和个位所组成的三位数能被8整除 (4)能被5整除的数.末尾是0或5 (5*)能被25整除的数.十位和个位所组成的两位数能被25整除 (6*)能被125整除的数.百位.十位和个位所组成的三位数能被125整除 (7)能被3整除的数,各个数位上的数字之和能被3整除 (8*)能被9整除的数.各个数位上的数字和能被 9 整除 (9

「数论基础」欧拉定理(费马小定理)

在阅读本篇之前,如果还不熟悉欧拉函数,可以参见另一篇介绍欧拉函数的「数论基础」欧拉函数. 定义:对于互质的两个正整数$a, n$,满足$a^{φ(n)} ≡ 1\  (mod\ n)$ 证明: 设集合$S$包含所有$n$以内与$n$互质的数,共有$φ(n)$个:     $S = \{ x_1, x_2, ..., x_{φ(n)} \} $ 再设集合$T$: $T = \{ a * x_1 \% n, a * x_2 \% n, ..., a * x_{φ(n)} \% n \} $ 由于$

你也可以手绘二维码(二)纠错码字算法:数论基础及伽罗瓦域GF(2^8)

摘要:本文讲解二维码纠错码字生成使用到的数学数论基础知识,伽罗瓦域(Galois Field)GF(2^8),这是手绘二维码填格子理论基础,不想深究可以直接跳过.同时数论基础也是Hash算法,RSA算法等密码学的入门基础. 二维码生成算法最为核心的就是编码规则和纠错码字的生成.本篇专门讲解纠错涉及到的伽罗瓦域(Galois Field).本文内容大部分是阅读<密码编码学与网络安全>后参考相关PPT编写,如有遗漏或不严谨地方请参考专业书籍. 数论基础 整除,因数,素数 设 a , b(b≠0)

数论基础学习总结(持续补充中)

数论基础 算术基本定理(唯一分解定理) 任何一个大于1的自然数都可以唯一分解成有限个素数的乘积 $N=p_1^{a_1}\times p_2^{a_2}\times...\times p_n^{a_n} | p_1<p_2<...<p_n ,a_i\in Z$ 上式中$p_i$为素数 有关素数筛 埃式筛法 就是拿一个已经筛选出的素数去排掉其他的数,比如2是素数,就用他筛掉2*2,2*3,2*4……,3是素数,就用他筛掉3*2,3*3,3*4……,把每个素数的倍数都筛掉,不过我们发现,3*

kuangbin带你飞---数论基础

又是几天过去,最近在刷数论基础和dp基础.kuangbin数论专题刷了差不多一大半吧.深深感jio到自己的菜.唉,温故而知新,所以决定在踩一遍坑点. Bi-shoe and Phi-shoe https://vjudge.net/problem/LightOJ-1370 题目大意:给出一些数字,对于每个数字找到一个欧拉函数值大于等于这个数的数,求找到的所有数的最小和. 分析:其实用欧拉筛打表欧拉函数值可以发现一个规律,质数的欧拉函数上升增加的速度远比其他数字快,所以此题只用找到第一个大于n的数即

数论基础总?结?

\(gcd\): inline int gcd(int a,int b){ return b?gcd(b,a%b):a;} 扩展欧几里得:求\(ax+by=gcd(a,b)\)的一组整数解. inline int Exgcd(int a,int b,int &x,int &y) { if(!b) {x=1,y=0;return a;} int Gcd=Exgcd(b,a%b,y,x); y-=a/b*x;return Gcd; } 费马小定理:\(a^{p-1}\equiv 1\mod p

数论基础——循环节和矩阵快速幂的运用

首先我们来看一道基础题: 题目链接:HDU1005 Number Sequence 题目描述: Number Sequence Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 147421    Accepted Submission(s): 35814 Problem Description A number sequence is

数论基础

听说明天AU爷ysy要给我们讲数论 赶紧预习一下好了 ①高斯消元 嗯这个就不多解释了- 题1 bzoj1013 球形空间产生器 嗯这题就是给你一个n维球体上的n+1个点,求圆心. 所以假设第i个点是(a[i][1],a[i][2]-a[i][n]) 那么我们就是要找一个点(x[1]-x[n])使得 (a[i][1]-x[1])^2+(a[i][2]-x[2])^2+-+(a[i][n]-x[n])^2=r^2 那么我们就有这样n+1个式子: (a[1][1]-x[1])^2+(a[1][2]-x