数学

数学

1 数论

1.1 模方程

  • 中国剩余定理:解决多个单元模方程组,形如 xaimodmi,且 mi 两两互质。令 M 为所有 mi 的乘积,记 wi=M/mi,使用 exgcd 得到满足 wipi+miqi=1pi,qi。令 ei=wipi,则方程组最后的解 x0=e1a1+e2a2++enan。简单证明:对 wipi+miqi=1 两边同时取模 mi,那么 ei=1;当 ji 时,两边同时取模,wjmi 倍数。

        scanf("%lld", &n);
        rep(i, 1, n) scanf("%lld%lld", &m[i], &a[i]), M *= m[i];
        rep(i, 1, n){
            int w = M / m[i]; exgcd(w, m[i]);
            int e = w * x;
            (x0 += e * a[i]) %= M;
        } printf("%lld\n", (x0 + M) % M);
    
  • BSGS(离散对数):求解模方程 axbmodn,其中 n 为素数。根据欧拉定理,我们只需检验 x=0,1,2,,n1 是不是解即可。我们不妨先只检验前 m 项,并把 ei=aimodn 保存。下面考虑 x=m,m+1,,2m1,此时若其中有解,则存在 i 满足 ei×ambmodn,即 eiambmodn。而上述合法的 ei 是可以通过 map 维护,O(logn) 得到的。同时,上述过程可推广至 x=im,im+1,,2im+1。当 m=n 时,时间复杂度最小,为 O(nlogn)

    std::map<int, int> Mp;
    inline void BSGS(){
        int m = (int)sqrt(n + 0.5), inv = pw(pw(a, n - 2, n), m, n);
        Mp.clear();
        Mp[1] = 0; int fac = 1ll;
        rep(i, 1, m - 1){
            fac = fac * a % n; if(!Mp.count(fac)) Mp[fac] = i;
        } fac = 1ll;
        rep(i, 0, m - 1){
            if(Mp.count(fac * b % n)) return printf("%lld\n", i * m + Mp[fac * b % n]), void();
            (fac *= inv) %= n;
        } printf("no solution\n");
    }
    

例题:

  1. UVA11426 GCD Extreme:fn=i=1n1gcd(i,n)=d|nd×φ(nd)O(nlogn) 预处理,O(1) 回答。

  2. UVA11754 Code Feat:数据分治。观察到条件个数较少,当 (M=mi)1e4 时,模数都较小,考虑 CRT;反之,模数都较大,考虑直接枚举,发现余数集越小、模数越大的数越优,所以枚举 ki/mi 最小的那个模数,枚举倍数暴力验证即可。

  3. UVA11916 Emoogle Grid:发现条件只限制了竖直方向上相邻的两个方格颜色不同。小奥,当格子上方为空或为特殊格时,有 K 种颜色;反之,有 K1 种颜色。显然行数 M 的范围是有限制的,即不能小于任何一个特殊格。统计包含所有特殊格的“不变部分”,方案数记为 cnt;若 cntR,考虑第一行“可变部分”的方案数,显然在特殊格正下方的格子会受影响,记它和“不变部分”的总方案数为 cnt;若 cntR,接下来每一行方案数 P=(K1)N,则有 Pm×cntRmodp,把 cnt 移到右边,套 BSGS 即可。

1.2 线性筛

  • 线性筛:

    inline void init(){
        g[1] = 1;//g[i]表示i的最小质因子
        for(int i = 2; i <= _; ++i){
            if(!vis[i]) pr[++tot] = i, g[i] = i;
            for(int j = 1; j <= tot and i * pr[j] <= _; ++j){
                vis[i * pr[j]] = 1, g[i * pr[j]] = pr[j];
                if(i % pr[j] == 0) break;
        }}}
    

例题:

  1. [POI2012] OKR-A Horrible Poem:好题。巧妙转化一下题意:如果存在一个长度 len 的循环节,一定满足 S[a,blen]=S[a+len,b],且 len|ba+1,充分必要。进一步发现,总长 L=ba+1=len0×cnt0,其中 len0 表示最小循环节长度,cnt0 表示最小循环节出现次数。这样第二个条件可以通过分解 L 求得最短循环节长度。判断循环节是否合法,根据第一条,我们可以维护哈希 O(1) 求得。线性筛加速质因数分解。

1.3 整除分块、积性函数、莫比乌斯反演、狄利克雷卷积、杜教筛

  • 整除分块:

    • 一般当式子中含有 ni 时,考虑使用整除分块优化计算复杂度。

    • 考虑当只做一次整除分块时,时复为 O(n12);套两层整除分块时,时复为 O(n34);根据不断积分推导与大胆猜想,推出套三层时,时复为 O(n78);则套 k 层时,时复为 O(n2k12k)。套的层数越多,越接近线性复杂度。

  • 积性函数:

    • 对于任意 ab,都有 f(a)f(b)=f(ab),则称 f(x) 为积性函数。

    • 对于任意 a,b,都有 f(a)f(b)=f(ab),则称 f(x) 为完全积性函数。

    • 对于任意积性函数,都有 f(1)=1

    • g(n)=d|nf(d),n1,则“f 是积性函数”与“g 是积性函数”互为充要条件。其中 g 称作 f 的和函数。还有 g(n)=i=1tj=0kif(ptj),其中 n=i=1tpiki。莫反就是针对 fg 的相互转换。

    • f,g 皆为积性函数,则 h(x)=f(x)g(x) 为积性函数,fg=d|xf(x)g(xd) 也为积性函数。

    • 常见积性函数包括欧拉函数 φ(n) 与莫比乌斯函数 μ(n)

    • 单位函数 ϵ(n)=[n=1]幂函数 Idk(n)=nk,id(n)=n常数函数 I(n)=1因数个数 d(n)=d|n1除数函数 σk(n)=d|ndk,σ(n)=d|nd,σ0(n)=d(n)

  • 莫比乌斯函数:

    • μ(x)={1x=10 p2|x(1)kn=p1p2pk

    • d|nμ(d)=[n=1] d|gcd(i,j)μ(d)=[gcd(i,j)=1]

    • 【补充】类似地,有 d|nφ(d)=n

  • 狄利克雷卷积:

    • 定义两个数论函数 f,g 的狄利克雷卷积为:(fg)(n)=d|nf(d)g(nd)

    • 狄利克雷卷积满足交换律、结合律、分配律。

    • f,g 为积性函数,则 (fg)(n) 也为积性函数。

    • 定义 ϵ 为狄利克雷卷积的单位元,ϵ(n)=[n=1],满足 (fϵ)(n)=f(n),证明显然。

    • (IdkI)(n)=d|ndk=σk(n),实际上只是写法不同,本质都是中间的那个 d|ndk

    • ϵ=μI,等价于 d|nμ(d)=[n=1],较为显然。

    • id=φI,等价于 d|nφ(d)=n,较为显然。

    • φ=idμ,等价于 d|ndμ(nd)=φ(n),而这个转化就极为有用,它实现了 φμ 之间的转化。

      证明:φ=φϵ=φ(μI)=(φI)μ=idμ

    • 与莫比乌斯反演相结合,等价于给定 g=fI,则有莫反 f=gμ

      证明:gμ=(fI)μ=fϵ=f

  • 杜教筛:

    • 杜教筛可在非线性时间内求积性函数的前缀和。对于求 f 的前缀和,构造 gf,则 g(1)S(n)=i=1n(fg)(i)d=2ng(d)S(nd)。快速求解 h=fg 的前缀和,使用数论分块并递归求解 S(nd)。不妨对 n23S(n) 用线性筛预处理出来,并在递归过程中使用 map 进行记忆化,则最终可将复杂度降至 O(n23)

      不妨假设所求 S(n)=inf(i),其中 f 为积性函数。构造 h=fg,H(n)=inh(i)H(n)=in(fg)(i)=ind|if(d)g(id)=dng(d)indf(i)=d=1ng(d)S(nd)如何得到 g(1)f(n)?将 [1,n] 的前缀和减去 [2,n] 的前缀和即可。得到:g(1)S(n)=in(fg)(i)d=2ng(d)S(nd)=H(n)d=2ng(d)S(nd)

    • μ 的前缀和:显然 μI=ϵ

      inline int getphi(int n){
          if(n <= _) return phi[n]; if(pmp.count(n)) return pmp[n];
          int res = n * (n + 1) / 2;
          for(int l = 2, r; l <= n; l = r + 1){
              r = (n / (n / l)); res -= (r - l + 1) * getphi(n / l);
          } return pmp[n] = res;
      }
      
    • φ 的前缀和:显然 φI=id

      inline int getmu(int n){
          if(n <= _) return mu[n]; if(mmp.count(n)) return mmp[n];
          int res = 1;
          for(int l = 2, r; l <= n; l = r + 1){
              r = (n / (n / l)); res -= (r - l + 1) * getmu(n / l);
          } return mmp[n] = res;
      }
      
    • f(i)=φ(i)×i 的前缀和:不妨取 g=id,则 h(i)=d|if(i)g(id)=i2。同时 g 的前缀和也可以快速算得。f(i)=φ(i)×i2 同理。例题:P3768 简单的数学题。

    • 【补充】12+22++n2=n(n+1)(2n+1)6

    • 【补充】13+23++n3=n2(n+1)24

  • 莫比乌斯反演:

    • g(n)=d|nf(d)f(n)=d|nμ(d)g(nd)

    • g(n)=n|df(d)f(n)=n|dμ(dn)g(d)

    • 莫比乌斯反演及莫比乌斯函数可以理解为容斥原理在数论中的一种表现形式。

    • 形式一:injm[gcd(i,j)=1]=xnnxmxμ(x),其中 i,j,x 都从 1 开始,nm

    • 形式二:injmgcd(i,j)=xnnxmxφ(x),其中 i,j,x 都从 1 开始,nm

    • 形式三:injmf(gcd(i,j))=xnnxmxd|xf(d)μ(xd),其中 i,j,x 都从 1 开始,nm

    • 以上三种形式都可以 O(n) 预处理,单次询问 O(n),数论分块维护。

    • 推广一:injm[gcd(i,j)=d]=xndndxmdxμ(x),其中 i,j,x 都从 1 开始,nm

例题:(默认 nm,用 ab 表示 a=1b

  1. SPOJ Visible Lattice Points:

N×N×N 三维可见格点数量。

injnkn[gcd(i,j,k)=1]=dninjnkn[d|i][d|j][d|k]μ(d)=dnnx3μ(d)

  1. HDU 4746 Mophues:

多次询问给定 n,m,p,求 injm[h(gcd(i,j)p],其中 h(x) 表示 x 的所有可重素因子个数。

injm[h(gcd(i,j)p]=dn[h(d)p]injm[gcd(i,j)=d]=dn[h(d)p]kndnkdmkdμ(k)=dn[h(d)p]d|xnnxmxμ(xd)=xnnxmxd|xμ(xd)[h(d)p]

大致过程就是先把 gcd 提出来,然后常规莫反,用 x 整理一下形式,最后把 d 放到一起。实现的话先 O(n) 预处理,发现 p 的最大值不超过 19,所以线性筛之后暴力统计上式右边部分即可,处理询问的时候使用数论分块 O(n) 回答,发现当 P20 时,上式右边是 μ(x)1,所以答案直接输出 n×m 即可。

  1. P3327 [SDOI2015] 约数个数和:

多次询问给定 n,m,求 injmd(ij),其中 d(x) 表示 x 的约数个数。

补充定理:d(ij)=x|iy|j[gcd(x,y)=1],证明通过构造每一种因子的取到方式即可。大多数题解 使用的方式都是对所求 f(p)=injmx|iy|j[gcd(x,y)=p] 及其和函数 g(n)=n|df(d) 进行简化,并得到 g(n) 的简单求法,再反演回 f(n),得到 f(1)。使用的是莫比乌斯反演的倍数形式。下面展示我个人仅使用莫比乌斯反演简单形式和暴力进行化式子的过程,一些默认的求和上指标就省略了:
injmx|iy|j[gcd(x,y)=1]=injmx|iy|jd[d|x][d|y]μ(d)=dμ(d)ijxy[x|i][y|j][d|x][d|y]=dμ(d)k1ndk2mdp1ndk1p2mdk21=dμ(d)indjmdnidmjd

两种方法最后得到的式子是相同的,然后 O(n) 预处理,O(Tn) 询问即可。

  1. P3768 简单的数学题:

给定 n,p,求 injnijgcd(i,j)p 取模的结果。n1e10,q1.1e9

形式一眼看上去很典。像在 P1829 [国家集训队] Crash的数字表格 / JZPTAB 中,求解 injmlcm(i,j)。这两道题从推式子方面相差不大,两道题都是对 gcd(i,j) 的化解,但此题数据范围较大,难度更胜一筹,所以作为代表性一题。通常来说,看到 gcd(i,j) 往往可以用 d|nφ(d)=n 转化为不带 gcd 的形式,然后再从 φ 入手考虑。这样会更简单些。但我一开始推的时候没有转化 gcd 的意识,所以就直接拿 μ 硬推了:(记 S(n)=ini
injnijgcd(i,j)=dnk1k2k1k2d3[gcd(k1,k2=1]=dnd3kndμ(k)k2S(ndk)2=anS(na)2a2d|adμ(ad)=ana2φ(a)S(na)2

省略了一些显然的推式子过程,重点在第三、四行。第三行用 a 代替了 dk,巧妙地通过枚举 a 来很大程度上简化了式子,构造出了狄利克雷卷积形式;第四行通过 μid=φ 直接变成单元形式,然后后面 S 使用整除分块,前半部分属于经典形式使用杜教筛,一共两层整除分块,时复 O(n23)

  1. P4318 完全平方数:

多次询问 T50,求第 k109 个不是某个完全平方数的正整数倍的数是多少。不考虑 1 作为完全平方数。

杜教筛神题!首先显然和 μ 有关,若 x 满足题意,则 μ(x)0。进一步地,为方便统计,我们考虑使用 μ2(x)。则题面转化为:求 ans,满足 x=1ansμ2(x)=k,μ2(ans)=1。搭配二分答案,记 S(n)=inμ2(i),则对于 mid,需检验 S(mid)k 是否为真。由于答案上界过大,无法使用线性筛,考虑杜教筛。则 f=μ2,考虑寻找一个合适的函数 g=[n=k2],k\N+。根据莫反的经验,我们知道,一个真值表达式形式的函数,可以通过改变其枚举方式,使表达式的值恒成立,从而使该函数在枚举时变为常函数

此时考虑 h(n)=(fg)(n)=d|nf(d)g(nd),发现当且仅当 nd 取到 n 的最大平方因子时,g(nd)=1,f(d)=1。而每个数都至少有 1 作为平方因子。故 inh(i)=n,即二者的卷积前缀和可轻松得到。继续考虑 H(n)d=2ng(d)S(nd) 的后半部分。显然当且仅当 d 为完全平方数时式子的值不为 0。所以,整个杜教筛式子可以直接表示为 ni=2nS(ni2)。此时我们无需再考虑 g 的前缀和。总时间复杂度为 O(106+TK23logK)。当然还有另解。打表做法此处暂不考虑。

考虑二分 + 容斥,因为 μ 具有天然容斥优势。考虑如何减去那些“某完全平方数的整数倍”的数的个数。我们依次考虑质数的平方,依次删去 22,32,52 的整数倍。考虑算重,以此类推,每次考虑若干互异质数乘积 n 的整数倍个数。显然 μ 就是容斥系数,而容斥上界是 MnM 为互异质数之积。所以 [1,n] 中合法的数的个数为:i=1nμ(i)ni2。总时间复杂度为 O(40559+TKlogK)

  1. SP27942 PROD1GCD - Product it again:

多次询问 T5,每次给定 n,m,求 injmgcd(i,j)1e9+7 取模的值。

放一道乘积形式的题。因为我们先前所学习的大部分形式与转化,都是基于加法之上的。所以对于乘法的形式,没有直接且 trival 的形式去直接化简。所以通常来讲,都是把因数合并,而因数的指数就变成相加形式了,所以我们就可以对指数进行讨论,回归到我们所熟悉的形态。回归本题,推式子:
injmgcd(i,j)=dndinjm[gcd(i,j)=d]=dndkndndkmdk=an(k|a(ak)μ(k))nama发现外面可以整除分块去做。考虑预处理中间那部分,记 f(n)=k|n(nk)μ(k)

显然有 f(1)=1,f(p)=p,p\P。通过观察数据范围,考虑通过线性筛把 f 筛出来。即使 f 并非积性函数,通过讨论 f(ab)b|abab\P)时 f(ab) 的取值,可以以此使用线性筛筛出 f。具体地,当 b|a 时,f(ab)=f(a);当 ba 时,f(ab)=1。总时间复杂度 O(n+Tnlogn),其中 logn 是快速幂的复杂度。

posted @   pldzy  阅读(8)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
历史上的今天:
2023-12-26 【CF30E】Tricky and Clever Password 题解(manacher + exKMP)
点击右上角即可分享
微信分享提示