• 【数论分块入门】


    数论分块

    通常用来解决 (sum_{i=1}^nlfloorfrac{n}{i} floor) 这种问题。

    我们代入 n = 10。

    i 1 2 3 4 5 6 7 8 9 10
    (lfloorfrac{n}{i} floor) 10 5 3 2 2 1 1 1 1 1

    可以看到后面有连续的 (i)(lfloorfrac{n}{i} floor) 相同。呈现块状分布

    每个块的起点 (l) 和终点 (r) 满足规律:(r=lfloorfrac{n}{lfloorfrac{n}{l} floor} floor)

    (lfloorfrac{n}{i} floor) 的有效取值只有 (O(sqrt n)) 个,求解 (sum_{i=1}^nlfloorfrac{n}{i} floor) 就可以快速的实现了。

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

    例题

    P2261 [CQOI2007]余数求和

    给出正整数 n 和 k,请计算

    [G(n, k) = sum_{i = 1}^n k mod i ]

    其中 (kmod i) 表示 k 除以 i 的余数。

    化简给出的式子 (k mod i=k-lfloorfrac{k}{i} floor imes i)

    [egin{aligned} G(n, k) &= sum_{i = 1}^n k mod i\ &=sum_{i=1}^n(k-lfloorfrac{k}{i} floor imes i)\ &=n imes k-sum_{i=1}^n(lfloorfrac{k}{i} floor imes i) end{aligned} ]

    对于 (sum_{i=1}^n(lfloorfrac{k}{i} floor imes i)),每个块我们求出 ([l,r]) 的和 乘 当前块的 (lfloorfrac{k}{i} floor)

    累加起来即可

    #include <bits/stdc++.h>
    #define pb push_back
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    const int mod = 1e9 + 7;
    const double eps = 1e-6;
    const int inf = 0x3f3f3f3f;
    const int N = 2e5 + 10;
    
    int main()
    {
        ll n, k;
        scanf("%lld%lld", &n, &k);
        ll ans = 0;
        for (ll l = 1, r; l <= min(n, k); l = r + 1) {
            r = min(n, k / (k / l));
            ans += (l + r) * (r - l + 1) / 2 * (k / l);
        }
        printf("%lld
    ", n * k - ans);
        return 0;
    }
    

    P1403 [AHOI2005]约数研究

    (f(i)) 表示 (i) 的约数的个数,给出 (n) ,请求出 (sum_{i=1}^{n}f(i))

    枚举约数 (i),显然,区间 ([1,n]) 中,有 (lfloorfrac{n}{i} floor) 个数字是 (i) 的倍数。

    答案即为 (sum_{i=1}^nlfloorfrac{n}{i} floor)

  • 相关阅读:
    打开LogCat以便查看日志
    sql语句优化
    IIS部署说明
    VM上Hadoop3.1伪分布式模式搭建
    C# 程序结构
    CSS笔记1:属性定位
    VS2013 添加控制台程序
    布局 Layout
    [游泳] 游泳学习课程
    "12306"台前幕后:五年利益之争 仓促上线
  • 原文地址:https://www.cnblogs.com/valk3/p/14046339.html
Copyright © 2020-2023  润新知