• [Luogu 2261] CQOI2007 余数求和


    [Luogu 2261] CQOI2007 余数求和

    <题目链接>


    这一定是我迄今为止见过最短小精悍的省选题了,核心代码 (4) 行,总代码 (12) 行,堪比小凯的疑惑啊。

    这题一看暴力很好打,然而 (10^{9}) 的范围注定会卡掉暴力。

    所以我们要用除法分块来优化。

    由题意得:(ans = sum_{i=1}^{n} k mod i)

    我们知道,(a mod b = a - b imes lfloor frac{a}{b} floor)

    因此,(ans = sum_{i=1}^{n} k - i imes lfloor frac{k}{i} floor = nk - sum_{i=1}^{n} i imes lfloor frac{k}{i} floor)

    我们用样例来打表找规律,发现 (lfloor frac{k}{i} floor) 分别在一定的区域内相等,如下表所示:

    (i) (1) (2) (3) (4) (5) (6) (7) (8) (9) (10)
    (lfloor frac{k}{i} floor) (5) (2) (1) (1) (1) (0) (0) (0) (0) (0)

    可见 (lfloor frac{k}{i} floor) 分成了 (3) 块,我们只需要计算 (n imes k) 减去每一块的和即可。

    首先枚举块的左边界 (l),并根据左边界和 (k) 计算出右边界 (r)

    (t = lfloor frac{k}{l} floor),分两种情况讨论:

    • (t eq 0),则 (r = min (lfloor frac{k}{t} floor , n))

    • (t = 0),则 (r = n)

    (请自行打草稿验证。)

    右边界有了,每一块的和也就可以计算出了。

    每一块的和 (=) 当前块的 (t) ( imes) 当前块元素个数 ( imes) 当前块 (i) 的平均值 (= t imes (r-l+1) imes (l+r) div 2)

    当前块处理完后,令 (l = r + 1),开始计算下一块,直到计算至 (n)

    除法分块就是这样,在莫比乌斯反演优化中也有作用的。

    给出最短小精悍的省选题代码。

    记得开long long!

    #include <algorithm>
    #include <cstdio>
    using std::min;
    long long n,k,ans;
    int main(int argc,char *argv[])
    {
    	scanf("%lld %lld",&n,&k);
    	for(long long l=1,r,t;l<=n;l=r+1)
    		r=(t=k/l) ? min(k/t,n) : n,ans-=t*(r-l+1)*(l+r)>>1;
    	printf("%lld
    ",ans+n*k);
    	return 0;
    }
    

    谢谢阅读。

  • 相关阅读:
    分数加减法
    两点距离
    1的个数
    Swift 了解(1)
    ARC快速入门
    ARC基本概念
    autorelease注意事项
    autorelease基本使用
    NSTimer的使用
    如何监听控件的行为
  • 原文地址:https://www.cnblogs.com/Capella/p/8476047.html
Copyright © 2020-2023  润新知