zoukankan      html  css  js  c++  java
  • 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 }
  • 相关阅读:
    16. 3Sum Closest
    17. Letter Combinations of a Phone Number
    20. Valid Parentheses
    77. Combinations
    80. Remove Duplicates from Sorted Array II
    82. Remove Duplicates from Sorted List II
    88. Merge Sorted Array
    257. Binary Tree Paths
    225. Implement Stack using Queues
    113. Path Sum II
  • 原文地址:https://www.cnblogs.com/AlphaWA/p/10217909.html
Copyright © 2011-2022 走看看