【算法笔记】整除分块

整理的算法模板合集: ACM模板


整除分块

整除分块,就是把 n n n 除以每一个 i i i 的商相同的分成一块

枚举 ( l , r ) (l,r) (l,r)区间即对于该分块区间任何一个数来说, n / r = n / l n/r = n/l n/r=n/l

移项得到 r = n / n / l r = n/n/l r=n/n/l

在这里插入图片描述

∑ i = 1 n ⌊ n i ⌋ \sum_{i=1}^{n}\lfloor\frac{n}{i}\rfloor i=1nin

模板代码:

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

luogu P2261 [CQOI2007]余数求和

在这里插入图片描述
我们知道 a % b a\%b a%b可以表示为 a − b ∗ ⌊ a b ⌋ a-b*\lfloor\frac{a}{b}\rfloor abba

所以 a n s = ∑ i = 1 n k − i ∗ ⌊ k i ⌋ = n ∗ k − ∑ i = 1 n i ∗ ⌊ k i ⌋ ans=\sum\limits_{i=1}^{n}k-i*\lfloor\frac{k}{i}\rfloor=n*k-\sum\limits_{i=1}^{n}i*\lfloor\frac{k}{i}\rfloor ans=i=1nkiik=nki=1niik
然后 ⌊ k i ⌋ \lfloor\frac{k}{i}\rfloor ik可以出发分块来做, ⌊ k i ⌋ \lfloor\frac{k}{i}\rfloor ik大约有 k \sqrt k k 种取值,所以时间复杂度 O ( k ) O(\sqrt k) O(k )

#include<cstdio>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<cstring>

using namespace std;
typedef long long ll;
const int N = 20007, M = 50007, INF = 0x3f3f3f3f;
const double eps = 1e-6;

ll n, k;

int main()
{
    scanf("%lld%lld", &n, &k);
    ll ans = n * k;
    // ⌊i/k⌋
    for(ll l = 1, r; l <= n; l = r + 1){
        if(k / l != 0)r = min((k / (k / l)) , n);
        else r = n;
        ans -= (r + l) * (k / l) * (r - l + 1) / 2;//先乘后除,不然会WA
        //区间内i的平均值 * (k / l) * 区间长度
    }
    printf("%lld\n", ans);
    return 0;
}

题解来源

在这里插入图片描述

杜教筛(上):整除分块,积性函数,欧拉与莫比乌斯

©️2020 CSDN 皮肤主题: 酷酷鲨 设计师:CSDN官方博客 返回首页