首页 > 其他分享 >『学习笔记』整除分块(数论分块)

『学习笔记』整除分块(数论分块)

时间:2023-08-26 21:33:08浏览次数:40  
标签:lfloor 分块 数论 dfrac rfloor times int ans 整除

简述

整除分块这个东西听起来不是很抽象,但是我理解起来的确有点抽象(可能因为我太菜了吧)。那就先放张图:

image

其实就是颜色相同的点被分成了一块。如果序列总长度是 \(n\),某一个区间左端点是 \(l\),那么 \(r = \lfloor \dfrac{n}{\lfloor \dfrac{n}{l} \rfloor} \rfloor\)。

所以整除分块主要是用来处理一些向下取整(或取模,因为取模也可以用向下取整的式子表示)的问题。

这个玩意的代码实现也挺模式化的,详见例题代码。

例题

UVA11526 H(n)

\(T\) 组数据,每组数据给定一个 \(n\),求 \(H(n) = \sum \limits _ {i = 1} ^ {n} \lfloor \dfrac{n}{i} \rfloor\)。

最基本的板子题,考虑整除分块,枚举到 \(l, r\),令 \(ans \leftarrow ans + (r - l + 1) \times \lfloor \dfrac{n}{i} \rfloor\)。

#include <bits/stdc++.h>
#define int long long
using namespace std;

int t, n, l, r, ans;

signed main() {
    scanf("%lld", &t);
    
    while (t--) {
        scanf("%lld", &n);

        l = 1; r = 0; ans = 0;

        while (l <= n) {
            r = n / (n / l);
            ans += (r - l + 1) * (n / l);
            l = r + 1;
        }

        printf("%lld\n", ans);
    }
}

P1403 [AHOI2005] 约数研究

给定 \(n\),设 \(f_i\) 为 \(i\) 的约数个数,求 \(\sum\limits _ {i = 1} ^ n f_i\)。

方法一:显然这是个积性函数,直接按着题意跑一遍线性筛即可。

方法二:显然最大的约数是 \(n\),可以转化为从 \(1\) 到 \(n\),每一个数能作为多少个数的约数,同上面的例题。

P2261 [CQOI2007] 余数求和

给定 \(n, k\),求 \(\sum\limits _ {i = 1} ^ n k \bmod i\)。

将 \(k \bmod i\) 转化成 \(k - i \times \lfloor \dfrac{k}{i} \rfloor\),然后求的时候乘上一个等差数列通项公式,就会做了。

#include <bits/stdc++.h>
#define int long long
using namespace std;

int n, k, l(1), r, ans;

signed main() {
    cin >> n >> k;

    ans = n * k;

    for (l = 1; l <= n; l = r + 1) {
        if (k >= l) r = min(k / (k / l), n);
        else r = n;
        ans -= (l + r) * (r - l + 1) / 2 * (k / l);
    }
    
    cout << ans << '\n';
}

P3935 Calculating

若 \(x\) 分解质因数结果为 \(x=p_1^{k_1}p_2^{k_2}\cdots p_n^{k_n}\),令\(f_x=(k_1+1)(k_2+1)\cdots (k_n+1)\),求 \(\sum\limits_{i=l}^r f_i \bmod 998244353\)。

这个题面的结论很常见,\(f_x\) 就是 \(x\) 约数个数,看我另一篇博客的解释。

跟前两个例题一样,就不废话了。

P2260 [清华集训2012] 模积和

给定 \(n, m\),求 \((\sum\limits_{i=1}^{n} \sum\limits_{j=1}^{m} (n \bmod i) \times (m \bmod j), i \neq j)\) \(\bmod 19940417\) 的值。

这题一看就是先推式子,然后就是乱搞。别的都好说,有两个地方需要注意。

有一项是 \(\sum\limits _ {i = 1} ^ {n} i^2 \times \lfloor \dfrac{n}{i} \rfloor \times \lfloor \dfrac{m}{i} \rfloor\)。

对于 \(i^2\) 的有一个结论:

\[\sum _ {i = 1} ^ n i ^ 2 = \dfrac{n \times (n + 1) \times (2 \times n + 1)}{6} \]

证明:

考虑构造。存在 \((n + 1) ^ 3 - n ^ 3 = 3 \times n ^ 2 + 3 \times n + 1\),从大到小递推再累加即可构造出来。

对于 \(\lfloor \dfrac{n}{i} \rfloor \times \lfloor \dfrac{m}{i} \rfloor\),就是假定先用 \(\lfloor \dfrac{n}{i} \rfloor\) 分好块,再用 \(\lfloor \dfrac{m}{i} \rfloor\) 把原有的块再分 \(m\) 个,代码实现就是 r = min(n / (n / i), m / (m / i))。时间复杂度只会影响常数级别。

一定要注意取模,还有写对符号!!我就是因为把取模打成乘号调了好长时间。

#include <bits/stdc++.h>
#define int long long

using namespace std;

const int P(19940417);

int n, m, ans, inv2(9970209), inv6(3323403);

inline int read() {
    int f(1), x(0);
    char c = getchar();
    for (; !isdigit(c); c = getchar()) if (c == '-') f = -1;
    for (; isdigit(c); c = getchar()) x = (x << 1) + (x << 3) + (c & 15);
    return f * x;
}

inline int Sum(int x) {
    return x * (x + 1) % P * (2 * x + 1) % P * inv6 % P;
}

inline int Range1(int l, int r) {
    return (l + r) * (r - l + 1) % P * inv2 % P;
}

inline int Range2(int l, int r) {
    return (Sum(r) - Sum(l - 1) + P) % P;
}

void solve1() {
    int res1 = n * n % P, res2 = m * m % P, res3 = n * n % P * m % P; // fu hao da cuo le
    
    for (int l = 1, r; l <= n; l = r + 1) {
        r = n / (n / l);
        res1 = (res1 + P - Range1(l, r) * (n / l) % P) % P;
    }

    for (int l = 1, r; l <= m; l = r + 1) {
        r = m / (m / l);
        res2 = (res2 + P - Range1(l, r) * (m / l) % P) % P;
    }

    ans = res1 * res2 % P;

    ans = (ans + P - res3) % P;
}

void solve2() {
    int a(0), b(0), c(0);

    for (int l = 1, r; l <= n; l = r + 1) {
        r = min(n / (n / l), m / (m / l));
        a = m * Range1(l, r) % P * (n / l) % P;
        b = n * Range1(l, r) % P * (m / l) % P;
        c = Range2(l, r) * (n / l) % P * (m / l) % P;
        ans = (ans + a + b - c + P) % P;
    }
}

signed main() {
    n = read(); m = read();
    if (n > m) swap(n, m);

    solve1();
    solve2();

    printf("%lld\n", ans);
}

P3579 [POI2014] PAN-Solar Panels

给定区间 \([a, b], [c, d]\),求 \(\max\{\gcd(i, j)\}, i \in [a, b], j \in [c, d]\)。

这道题很好,并不是板子,需要一定思考。

为了方便,先设 \(b = \min(b, d)\)。

显然我们知道,答案在 \([1, b]\) 这个区间里。一个很暴力的思路就是直接把答案 \(i\) 从 \(1\) 枚举到 \(b\),显然会寄,那么就用整除分块优化,显然每次枚举到的是一段区间 \([l, r]\),也就是对于 \(\forall i \in [l, r], \dfrac{b}{i}\) 都相等。根据题意要选最大的,所以直接选 \(r\) 即可。

还有一个性质,就是若区间 \([l, r]\) 存在 \(x\) 的倍数,则 \(\lfloor \dfrac{l}{x}\rfloor < \lfloor \dfrac{r}{x} \rfloor\)。(这里的 \(l, r\) 不同于上面的 \(l, r\))

这样就可以在枚举 \(r\) 的同时判断 \(r\) 是否合法了。

#include <bits/stdc++.h>
using namespace std;

int n, a, b, c, d, ans;

int main() {
    scanf("%d", &n);

    while (n--) {
        scanf("%d%d%d%d", &a, &b, &c, &d);

        for (int l = 1, r; l <= min(b, d); l = r + 1) {
            r = min(b / (b / i), d / (d / i));
            if (b / i * i >= a && d / i * i >= c) ans = r;
        }

        printf("%d\n", ans);
    }
}

标签:lfloor,分块,数论,dfrac,rfloor,times,int,ans,整除
From: https://www.cnblogs.com/Chronologika/p/17659479.html

相关文章

  • 数论-同余与扩展欧几里得详解(附例题及代码)
    数论-同余与扩展欧几里得详解(附例题及代码)注意:这篇文章的信息量会有一点多,请耐心看完一.同余1.1同余的定义给定一个正整数m,如果两个整数a和b满足a-b能够被m整除,即(a-b)/m得到一个整数,那么就称整数a与b对模m同余,记作a≡b(modm)简单来说,对于x,y,若x%p=y%p,即x,y对于p的余数......
  • 【学习笔记】简单数论-高斯消元与线性空间
    友情提示本博客内部分内容因缺乏样例,可能晦涩难懂,建议参考蓝书或者数论小白都能看懂的线性方程组及其解法。线性方程组线性方程组是由\(M\)个\(N\)元一次方程共同构成的。线性方程组的所有系数可以写成一个\(M\)行\(N\)列的系数矩阵,再加上每个方程等号右侧的常数,可......
  • 数论笔祭 - 林学长的第二数学
    林学长讲课笔记极限\(\lim_{x\tox_0}f(x)\)考虑运算法则:一般来说,函数的和差商积的极限等于函数的极限的和差商积。但是例外:\[\lim_{x\to3}\frac{x-3}{x^2-9}\]考虑极限约去\(x-3\)得到:\[\lim_{x\to3}\frac1{x+3}=\frac16\]如果约不掉?但是……......
  • 树分块学习笔记
    思想树分块是一种能解决部分操作树上一条链的一种算法。回忆下序列上的分块,其最精髓的地方在于将序列分成许多段,如果操作的区间包括了某一段,则直接使用整体处理这一段。我们也要使用某种方法使得操作的链也被分成许多块,但像dfs序等并不一定能保证整段的大小稳定。先设定一个......
  • 【学习笔记】简单数论-同余
    同余若整数\(a\)和整数\(b\)除以正整数\(m\)的余数相等,则称\(a,b\)模\(m\)同余,记为\(a\equivb\pmod{p}\)。性质自反性:\(a\equiva\pmod{p}\)对称性:若\(a\equivb\pmod{p}\),则\(b\equiva\pmod{p}\)。传递性:若\(a\equivb\pmod{p},b\equiv......
  • 【学习笔记】简单数论-快速幂
    luoguP1226【模板】快速幂|取余运算#include<bits/stdc++.h>usingnamespacestd;#definelllonglong#definesortstable_sort#defineendl'\n'llqpow(lla,llb,llp){llans=1;while(b>0){if(b&1){......
  • 【学习笔记】简单数论-最大公约数
    一个整数\(N\)的约数上界为\(2\sqrt{N}\)。\(1\simN\)每个数的约数个数的总和大约为\(N\timeslogN\)。取模运算性质\((a+b)\bmodp=((a\bmodp)+(b\modp))\modp\),反之亦成立。\((a-b)\bmodp=((a\bmodp)-(b\modp))\modp\),反之亦成立。\((a\tim......
  • 【学习笔记】简单数论-质数
    质数的个数是无限的。试除法:若一个正整数\(N\)为合数,则存在一个能整除\(N\)的数\(T\),其中\(2\leT\le\sqrt{N}\)。时间复杂度为\(O(\sqrt{N})\)。代码实现boolisprime(intn){ if(n<2) returnfalse; for(inti=2;i<=sqrt(n);i++) if(n......
  • 「Note」数论方向 - 同余相关
    1.扩展欧几里得算法1.1.介绍扩展欧几里得算法用于求\(ax+by=\gcd(a,b)\)的一组特解(整数解)。推导如下:设\(\begin{cases}ax_1+by_1=\gcd(a,b)\\bx_2+(a\modb)y_2=\gcd(b,a\modb)\end{cases}\)由欧几里得算法可知\(\gcd(a,b)=\gcd(b,a\modb)\)。联立有:\[ax_1+by_1=bx......
  • 数论题目
    小凯的疑惑题面:Link分析:题意简述:给定两个互质的正整数$x,y$,求最大不能被表示成$ax+by$的数($a,b$满足$0\lea,b$ 且为整数)不妨设$x<y$,答案为$ans$如果:$ans\equivmx(mod\,y)(1\lem\ley-1)$则$ans=mx+ny(1\lem\ley-1)$注意这里的$n$可以为非正整数显......