zoukankan      html  css  js  c++  java
  • BZOJ1257:[CQOI2007]余数之和——题解+证明

    http://www.lydsy.com/JudgeOnline/problem.php?id=1257

    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。

    Output

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

    Sample Input

    5 3

    Sample Output

    7

    ————————————————————————————————————————————

    参考了http://blog.csdn.net/u013598409/article/details/47037031

    预备知识:

    1.等差数列求和。

    2.k%i=k-k/i*i(除号均为整除,下同)

    由知识2可得我们所求的答案为n*k-∑(k/i*i)

    我们也可知道,i在一定的范围内时,k/i的值将唯一。

    所以这给我们一个想法,即固定w=k/i,将答案变为n*k-∑(w*i)

    那么求∑i就需要知道这个区间的左右端点,左端点即是i,而右端点r=k/w。

    证明:显然i*w<=k,那么i<=k/w,取等时为边界。

    然后利用等比数列求和的想法即可求得答案。

    接下来设s=根号n(向下取整),简单证明算法复杂度为O(s):

    显然(但我不会证明)s+m>s>n/(s+m)也就是说s处于一个对称轴的位置,他之后的数(即[s+1,n])被n除后一定可以映射到[1,s]之中,即最大数量为s个。

    那么反着推[1,s]被n除后映射的最大数量也应该是s个

    所以我们能够发现w的取值个数最大有2*s个。

    算法复杂度为O(2*s)

    #include<cstdio>
    #include<queue>
    #include<cctype>
    #include<cstring>
    #include<cmath>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    int main(){
        ll n,k;
        scanf("%lld%lld",&n,&k);
        ll ans=n*k;
        if(n>k)n=k;
        int l,r,j;
        for(int i=1;i<=n;i=r+1){
        j=k/i,l=i,r=k/j;
        if(r>=n)r=n;
        ans-=(ll)(l+r)*(r-l+1)*j/2;
        }
        printf("%lld
    ",ans);
        return 0;
    }
  • 相关阅读:
    redis对string进行的相关操作
    bs4解析库
    redis对键进行的相关操作
    python常见的函数和类方法
    一些(也许)有用的技巧以及注意事项
    【复健内容】NOIP2020 题解
    类欧几里得的一个方法
    UOJ Round #12
    Goodbye Yiwei
    UOJ Round #11
  • 原文地址:https://www.cnblogs.com/luyouqi233/p/8193093.html
Copyright © 2011-2022 走看看