• BZOJ1257(数论知识)


    感觉做法很神奇……想不到啊qwq

    题目:

    Description

    给出正整数n和k,计算j(n, k)=k mod 1 + k mod 2 + k mod 3 + … + k mod n的值
    其中k mod i表示k除以i的余数。
    例如j(5, 3)=3 mod 1 + 3 mod 2 + 3 mod 3 + 3 mod 4 + 3 mod 5=0+1+0+3+3=7

    Input

    输入仅一行,包含两个整数n, k。
    1<=n ,k<=10^9

    Output

    输出仅一行,即j(n, k)。

    Sample Input

    5 3

    Sample Output

    7
     
    第一步,每个数x对ans的贡献为:k - k / x * x,所以ans = n * k - Σ(int)(k / x) * x;而怎样小于O(n)地求Σ里的一串呢?只好用数学知识压缩计算范围。
     
    第二步,存在g(x) = (int)(k / (int)(k / x)),(如果没有int的取下界那gx就是x了,以下gx不写括号了啊),gx >= (int)(k / (k / x)) == (int)x == x,因此进一步有(int)(k / gx) <= (int)(k / x)(想一想为什么)。
     
    第三步,(int)(k / gx) >= (int)(k / (k / (int)(k / x))) == (int)(k / x)。这个结论与第二步末尾结合一下可得,(int)(k / gx) == (int)(k / x)。这个推论就很重要了,意味着对于i∈[x, gx],(int)(k / i)都是一样的,而我们要求的Σ里面那一坨,不过就是(int)(k / i) * i,那[x, gx]就是等差数列了,可以O(1)算出这一区间的值,而不是遍历。
     
    第四步,如此,遍历的将是区间[1, g(1))],[g(1)+1, g(g(1)+1)],……那这样的区间有多少个?复杂度可以承受吗?回答是,最多有2√k个区间。x <= √k时,最多只有√k个取值;x > √k时,考虑每个区间的“特征值”(int)(k / x) < √k,因此区间的个数还是小于√k。至于x > k时,都是k / x都是0了……
     
     1 #include <cstdio>
     2 #include <algorithm>
     3 #define ll long long
     4 #define R(x) scanf("%lld", &x)
     5 #define W(x) printf("%lld
    ", x)
     6 
     7 int main() {
     8     ll n, k;
     9     R(n), R(k);
    10 
    11     ll ans = n * k;
    12     for (int i = 1, gx; i <= n; i = gx + 1) {
    13         gx = k / i ? std::min(k / (k / i), n) : n;
    14         ans -= (k / i) * (gx - i + 1) * (i + gx) / 2;
    15     }
    16 
    17     W(ans);
    18 }
  • 相关阅读:
    protobuf配置与使用
    gvim配置
    html div+css做页面布局
    php info
    开源相关工具汇总
    mem 0908
    linux dd指令
    java面试(2)--大数据相关
    Java基础面试题(1)
    转自ruby迷: 使用Net::SSH和Net::SCP编写Linux服务器管理脚本
  • 原文地址:https://www.cnblogs.com/AlphaWA/p/10217909.html
Copyright © 2020-2023  润新知