中等数论详解 [提高数论,积性函数)

呼~好久没更了

说得根有人看似的

魔改自DZYdalao的ppt

整除和剩余

设a,b是两个整数,\(b\neq0\),则存在唯一的q和r,使得

a=qb+r,\(0 \leq r <|b|\)

即q=a/b,r=a%b

这种式子叫带余除法

若r=0,则称b整除a,记为b|a

若a和b除以m的余数相同,称为a和b模m同余,记为

\(a \equiv b (mod m)\)

在模 m 的意义下,余数相同的归为一个集合,那么所有整数被分为 m个不同的集合,模 m 的余数分别为 0,1,2,3,...,m − 1,这些集合被称为模 m 剩余类(同余类)。

一个整数的集合,对 m 取模后,余数遍历了 0,1,2,3,...,m − 1,那么该整数集合是模 m 的完全剩余系。

素数

定义:素数(质数)是大于 1 的正整数,并且除了 1 和它本身不能被其他正整
数整除。大于 1 的非素数的正整数称为合数。

素数定理:

\(\pi(x)\)表示小于x的素数一共有多少个

那么有\(\pi(x)\approx\frac{x}{ln x}\)

这东西一般人可能证不出来

而且好像没啥用

唯一分解定理

每一个正整数都可以唯一的表示成质数的乘积,其中质数因子从小到大出现。换句话说,任意正整数 n 可以写成:

\(n = p_{1}^{a_{1}} p_{2}^{a_{2}} ... p_{k}^{a_{k}}\)
\(= \prod_{i=1}^{k} p_{i}^{a_{i}}\)

void devide(int x)
{
    tot=0;
    for (int i=1;i<=cnt;i++)
        if (x%pl[i]==0)
        {
            a[++tot]=pl[i];
            p[tot]=0;
            while (x%pl[i]==0)
            {
                x/=pl[i];
                p[tot]++;
            }
        }
    if (x!=1)
    {
        a[++tot]=x;
        p[tot]=1;   
    }
}

可以做到\(O(\sqrt{N})\)预处理,\(O(\frac{\sqrt{N}}{log \sqrt{N}})\)回答

当然如果询问很多,也可以用欧拉筛实现\(O(N)\)预处理,\(O(logN)\)回答(不知道欧拉筛的后面有)

即在欧拉筛时顺便统计每个数的最小质因子,每次除以最小质因子,由于每个数最多有\(O(logN)\)个质因子,所以是对数级别的

bool np[MAXN];
int pl[MAXN],mp[MAXN],cnt;
void init()
{
    np[1]=1;
    for (int i=2;i<=MAX;i++)
    {
        if (!np[i]) pl[++cnt]=i,mp[i]=i;
        for (int j=1;j<=cnt&&i*pl[j]<=MAX;j++)
        {
            np[i*pl[j]]=1;
            mp[i*pl[j]]=pl[j];
            if (i%pl[j]==0) break;
        }
    }
}
int a[MAXN],p[MAXN],tot;
void devide(int x)
{
    while (x!=1)
    {
        int t=mp[x];
        a[++tot]=t,p[tot]=0;
        while (x%t==0) x/=t,++p[tot];
    }
}

例题:poj 3421

题意:
给定 X,让你构造序列 $a_{1} ,a_{2} ,...,a_{n} $,满足 \(a_{i}< a_{i+1} ,a_{i} |a _{i+1} ,a_{n} = X\)。求最大的 n,以及在最大 n 下的方案数。

把 X 质因数分解,把质因子任意排列,那么这个前缀积对应着一个最优序列。

第二问是组合数学,就不讲了

主要是不想写公式

素数筛法

由反证法,可知如果n是合数,那么它一定有一个小于\(\sqrt{n}\)的因数

可以得到以下判定法:

bool isprime(int x)
{
    if (x==1)
        return false;
    for (int i=2;i*i<=x;i++)
        if (x%i==0)
            return false;
    return true;
}

瞎推一波可以发现,如果x是素数,那么它要么是2,要么%6=1或5

可以优化:

bool isprime(int x)
{
    if (x==1)
        return false;
    if (x==2)
        return true;
    if (x%6!=1&&x%6!=5)
        return false;
    for (int i=2;i*i<=x;i++)
        if (x%i==0)
            return false;
    return true;
}

复杂度O(\(\sqrt{n}\)

素数筛法

如果我们想知道1~n 中所有素数,那将是O(\(n\sqrt{n}\))的

其实可以一次性把所有素数筛出来

我们可以枚举 1 到 n 所有数,如果枚举一个数的时候它没有被筛去,那么说明他是一个质数。

由调和级数,复杂度\(O(NlogN)\)

埃拉托斯特尼筛法

我们可以枚举 1 到 n 所有数,如果枚举一个数的时候它没有被筛去,那么说明他是一个质数。

对于质数,我们把大于它们且是它们倍数的数筛去。

复杂度O(NloglogN),基本够用了

int np[MAXN],pl[MAXN],cnt;
void init()
{
    np[1]=1;
    for (int i=2;i<=n;i++)
        if (!np[i])
        {
            pl[++cnt]=i;
            for (int j=i*2;j<=n;j+=i)
                np[i]=1;
        }
}

如果你觉得一堆log碍眼还有一种严格\(O(N)\)的欧拉筛法

前几种筛法浪费时间的主要原因就是同一个合数被筛了很多遍,而欧拉则保证每个合数只被他的最小质因子

先贴代码:

bool np[MAXN];
int pl[MAXN],cnt;
void init()
{
    np[1]=1;
    for (int i=2;i<=MAX;i++)
    {
        if (!np[i]) pl[++cnt]=i;
        for (int j=1;j<=cnt&&i*pl[j]<=MAX;j++)
        {
            np[i*pl[j]]=1;
            if (i%pl[j]==0) break;
        }
    }
}

上述代码其他都好理解,主要是if (i%pl[j]==0) break;

在上面描述中,注意\(i*pl[j]\)是被\(pl[j]\)筛的而不是\(i\)

那么,如果我们发现\(i\)含有\(pl[j]\),那么\(i\)一定含有一个不超过\(pl[j]\)的质数,那么\(i\)乘上后面的质数的最小质因子永远不可能是那个质数,就可以直接跳出

这样就可以保证所有数只被筛一次

例题:poj 2689

题意:给定 L,R,保证$ L,R ≤ 10^{9} ,R−L ≤ 10^{5}$ ,问 [L,R] 中距离最近的两个质数的距离。

根据上面那个“如果n是合数,那么它一定有一个小于\(\sqrt{n}\)的因数”

也就是说\(\sqrt R\)以内的数可以筛掉[L,R]

然后瞎搞就可以了

欧拉函数

定义:\(\varphi(x)\)=1~n中与n互质的数

性质:

1.p是素数 ⇔ \(\varphi(p)\)=p-1(很好证明)

2.设 p 是一个素数,a 是一个正整数,那么

\(\varphi(p^{a}) = p^{a} - p^{a-1} = p^{a-1}(p-1)\)

也好证

3.如果 m,n 互质,那么 φ(mn) = φ(m)φ(n),这叫欧拉函数的积性。注意要互质。

可以构造一个矩阵:

1451707-20180901192816324-683883455.png

然后就可以证了

4.如果
\(n = \prod_{i=1}^{k} p_{i}^{a_{i}}\),
\(\varphi(n) = n \prod_{i=1}^{k} {(1-\frac{1}{p_{i}})}\)

可以通过意识流积性证明

5.\(\sum_{d|n} \varphi(d) = n\)

什么?证明?

你找一个n,然后把\(\frac{1}{n},\frac{2}{n},...,\frac{n-1}{n}\)写出来,然后化成最简分数,再按分母归类,然后就会发现一件神奇的事

欧拉定理

如果 a,m 互质,那么:

\(a^{\varphi(m)} \equiv 1 (mod m)\)

证明留作课后习题

特殊情况:费马小定理

当 p 是质数,\(a \neq p\) 时,有 \(a ^ {p-1} ≡ 1 (mod p)\)

广义欧拉定理

若 a,m 互质,则 \(a^{n} ≡ a^{n \% φ(m)} (mod m)。\)

若 a,m 不互质,则:

\(a ^{n} ≡ a^{n \% φ(m)}(mod m)\qquad (n < φ(m))\)

\(a^{n} ≡ a^{n \% φ(m)+φ(m)}(mod m)\qquad otherwise\)

(例题:poj3090)[http://poj.org/problem?id=3090]

题意:
给出范围为 (0,0) 到 (n,n) 的整点,你站在原点处,问有多少个整点可见。

1451707-20180901222627138-1839896132.png

易知(x,y)=1

然后是个很裸的莫比乌斯反演

枚举横坐标 x,那么不被挡住的纵坐标一定与 x 互质。
ans = 2$\sum _{i=1} ^{n}{\varphi(i)} $ + 3,3 对应 (1,0),(0,1),(0,0) 三点。

线性同余方程

欧几里得算法

一个广为人知的定理:gcd(a,b) = gcd(b,a%b)

然后可以递归了

每次至少一个数减少一半,故时间复杂度为O(log(a+b))

int gcd(int a,int b)
{
    return b? gcd(b,a%b):a;
}

扩展欧几里得算法

考虑如何解下面这个不定方程:

\(ax+by=gcd(a,b)\)

看gcd不顺眼

\(gcd(a,b) = gcd(b,a \% b)\)

左边写出来:

\(bx’+(a \% b)y’=gcd(b,a \% b)\)

\(ax+by=bx’+(a \% b)y’\)

%是什么?

\(ax+by=bx’+(a-b[\frac{a}{b}])y’\)

整理一下:

\(ax+by=ay’+b(x’-[\frac{a}{b}]y’)\)

可得:

\(x=y’,y=x’-[\frac{a}{b}]y’\)

然后又可以递归啦

边界为b=0,即ax+0y=a,假装a=1,y=0

迭代回去就可以得到原方程的一组特解

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

至于通解的话乱搞就行了

扩展欧几里得算法的扩展

一般不定方程

原来那个方程好鬼畜啊,有没有更通用的呢?

即ax+by=c

很(wo)容(bu)易(hui)证明,这个方程有解的充要条件是gcd(a,b)|c

所以把x和y乘上\(\frac{c}{gcd(a,b)}\)就可以了

什么?通解?

把a和b同时除以gcd得到a',b'

\(x'=x+k \times b',y' = y - k \times a'(k \in Z)\)就是通解

同余方程

\(ax \equiv b(mod c)\)

可得ax+cy=b (注意x,y可以为负数)

然后套exgcd就好了

[例题:poj1061](http://poj.org/problem?id=1061

题意:
有一个长为 L 的首尾相连的数轴,有两只青蛙 A,B,它们初始点分别为s,t,A 青蛙每步往右跳 p 步,B 青蛙每步往右跳 q 步,现在它们同时开始跳,求同时跳多少步后能跳到同一点上,若无解则输出”Impossible”.

列出方程即可求解

逆元

定义:(a,m)=1,\(ab \equiv 1 (mod m)\),则称 b 为 a 模 m 意义下的逆元。记为\(a^{-1}\)

显然,模意义下的除法可以用乘逆元来代替。

求法:

1.费马小定理

当m为质数时,\(a^{-1}=a^{m-2}\)

2.扩展欧几里得

即求\(ax \equiv 1 (mod m)\)

3.欧拉定理

由于要写欧拉函数,比较麻烦,这里就不介绍了

筛法:

1.首先有\(1^{-1}=1\)

2.令

\(m=ki+r,0 \leq r<i\)

放到mod m下

\(ki+r=0\)

同时乘以\(i^{-1}r^{-1}\)

\(kr^{-1}=-i^{-1}\)

\(i^{-1}=-[m/i](m\%i)^{-1}\)

然后瞎取一下模就可以了

inv[1]=1;
for (int i=2;i<p;i++)
    inv[i]=(long long)(p-p/i)*inv[p%i]%p;

筛阶乘逆元

先递推求出阶乘

然后随便哪个方法求出fact[n]的逆元 注意判断有没有0,否则要找最后一个非0的

然后根据除法可用乘逆元代替再推回去

fact[1]=1;
for (int i=2;i<=n;i++)
    fact[i]=fact[i-1]*i%MOD;        
inv[n]=qpow(fact[n],MOD-2);
for (int i=n-1;i>=1;i--)
    inv[i]=inv[i+1]*(i+1)%MOD;

常用于组合数学

中国剩余定理

中国剩余定理主要解决以下方程:

\(x \equiv a_{1}\qquad(mod m_{1})\)

\(x \equiv a_{2}\qquad(mod m_{2})\)

... ...

\(x \equiv a_{n}\qquad(mod m_{n})\)

其中\(m_{1},m_{2},...,m_{n}\)两两互质

解此方程的难点在于需要同时满足n个方程

那我们考虑一下如何把限制减少

由于模的可加性,所以对于第i个方程,x加上\(m_{i}\)后依然满足

我们不妨令x=\(\sum_{i=1}^{n}( k_{i}\frac{M}{m_{i}})\),其中\(M=\prod _{i=1}^{n} m_{i}\)

这样第i个方程就只受\(k_{i}\frac{M}{m_{i}}\)的影响

那我们就强制让它等于\(a_{i}\),即令\(k_{i}=a_{i}(\frac{M}{m_{i}})^{-1}\)

然后加起来就可以了

int ans=0,lcm=1;
for (int i=1;i<=k;i++)
     scanf("%lld",&a[i]);
for (int i=1;i<=k;i++)
     scanf("%lld",&b[i]),lcm*=b[i],a[i]=(a[i]%b[i]+b[i])%b[i];
for (int i=1;i<=k;i++)
{
     int temp=lcm/b[i];
     int x,y;
     exgcd(temp,b[i],x,y);
     x=(x+b[i])%b[i];
     ans=(ans+qmul(qmul(a[i],temp,lcm),x,lcm))%lcm;
}
printf("%lld",(ans+lcm)%lcm);

扩展中国剩余定理

如果\(m_{k}\)不互质,该怎么办呢?

我们换一种思路

假设我们求出了前k-1个方程解为x,\(M_{k}= \prod _{i=1}^{k-1} m_{i}\)

即通解为\(x+tM_{k}\)(t为整数)

对于第k个方程:

\(x+tM_{k} \equiv a_{k} \qquad (mod m_{k})\)

\(tM_{k} \equiv a_{k} - x\qquad (mod m_{k})\)

然后又可以扩欧了。

如果该方程无解,说明原方程无解

int M=m[1],ans=r[1],x,y;
for (int i=2;i<=n;i++)
{
    int a=M,b=m[i],c=(r[i]-ans%b+b)%b;
    int gcd=exgcd(a,b,x,y),bg=b/gcd;
    x=qmul(x,c/gcd,bg);
    ans+=x*M;
    M*=bg;
    ans=(ans%M+M)%M;
}

貌似和中国剩余定理没任何关系

Baby-Step-Giant-Step

简称BSGS,中文名分块大步小步法,拔山盖世,北上广深等

这是一种思想,主要用于处理这种方程

\(a^{x} \equiv b (mod c)\)

根据抽屉原理,它的周期最多为c,所以暴力枚举是O(c)的

BSGS法:

\(B=\sqrt{c} ,x=iB-y\)

\(a^{x}=a^{iB-c}\)

可得\(a^{iB-y} \equiv b \qquad (mod c)\)

然后\(a^{iB} \equiv a^{y}b \qquad (mod c)\)

然后枚举i,把\(a^{iB}\)丢进Hash,值为iB

再枚举y,检查\(a^{y}b\)是否出现,如果有说明解为iB-y

如果没有出现说明无解

复杂度O(\(\sqrt{c}\))

按理说写Hash可以做到O(1)查询,但除非遇到用(sang)心良(bing)苦(kuang)的出题人,用map一般就能过了

void init()
{
    len=ceil(sqrt(c));
    int del=qpow(a,len,c),now=del;
    m[now]=len;
    for (int i=2;i<=len;i++)
    {
        now=(now*del)%c;
        m[now]=i*len;
    }
}
int BSGS(int b)
{
    for (int j=0,now=1;j<=len;j++,now=(now*a)%c)
        if (m[(now*b)%c])
            return m[(now*b)%c]-j;
}

最后用一道神题结束这篇文章:

SDOI 2011 计算器

数论大杂烩

第一个直接快速幂

第二个扩欧,然后瞎取模使其最小

第三个BSGS,注意是求最小非负整数解,所以上面的写法是错的(调了好久QAQ)

应该随时记录最小值

还有如果用-1表示无解要注意不要把它%掉了

这个学了之后就是莫比乌斯反演之类的,以后可能会写

转载于:https://www.cnblogs.com/lstoi/p/9571204.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ava实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),可运行高分资源 Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现
C语言是一种广泛使用的编程语言,它具有高效、灵活、可移植强等特点,被广泛应用于操作系统、嵌入式系统、数据库、编译器等领域的开发。C语言的基本语法包括变量、数据类型、运算符、控制结构(如if语句、循环语句等)、函数、指针等。下面详细介绍C语言的基本概念和语法。 1. 变量和数据类型 在C语言中,变量用于存储数据,数据类型用于定义变量的类型和范围。C语言支持多种数据类型,包括基本数据类型(如int、float、char等)和复合数据类型(如结构体、联合等)。 2. 运算符 C语言中常用的运算符包括算术运算符(如+、、、/等)、关系运算符(如==、!=、、=、<、<=等)、逻辑运算符(如&&、||、!等)。此外,还有位运算符(如&、|、^等)和指针运算符(如、等)。 3. 控制结构 C语言中常用的控制结构包括if语句、循环语句(如for、while等)和switch语句。通过这些控制结构,可以实现程序的分支、循环和多路选择等功能。 4. 函数 函数是C语言中用于封装代码的单元,可以实现代码的复用和模块化。C语言中定义函数使用关键字“void”或返回值类型(如int、float等),并通过“{”和“}”括起来的代码块来实现函数的功能。 5. 指针 指针是C语言中用于存储变量地址的变量。通过指针,可以实现对内存的间接访问和修改。C语言中定义指针使用星号()符号,指向数组、字符串和结构体等数据结构时,还需要注意数组名和字符串常量的特殊质。 6. 数组和字符串 数组是C语言中用于存储同类型数据的结构,可以通过索引访问和修改数组中的元素。字符串是C语言中用于存储文本数据的特殊类型,通常以字符串常量的形式出现,用双引号("...")括起来,末尾自动添加'\0'字符。 7. 结构体和联合 结构体和联合是C语言中用于存储不同类型数据的复合数据类型。结构体由多个成员组成,每个成员可以是不同的数据类型;联合由多个变量组成,它们共用同一块内存空间。通过结构体和联合,可以实现数据的封装和抽象。 8. 文件操作 C语言中通过文件操作函数(如fopen、fclose、fread、fwrite等)实现对文件的读写操作。文件操作函数通常返回文件指针,用于表示打开的文件。通过文件指针,可以进行文件的定位、读写等操作。 总之,C语言是一种功能强大、灵活高效的编程语言,广泛应用于各种领域。掌握C语言的基本语法和数据结构,可以为编程学习和实践打下坚实的基础。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值