zoukankan      html  css  js  c++  java
  • [CQOI2007]余数求和

    题意描述

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

    样例啊,那我就随便写两个啦

    9 3 输出 19
    10 5 输出 30

    划重点

    数据范围n,k<=1e9

    咳咳,进入真正重点

    首先数据范围就决定了你的暴力已经阵亡
    那么你现在肯定满脑子期待着一个O(1)或者O(logn)其实O(根号n)的算法

    标准的公式啊代码啊可以移步这里

    算是一个友情链接,对面是个手推公式的大佬
    不过蒟蒻不太会推公式
    但是

    咳咳,我会找规律啊

    来,先看一个表

    10 0
    11 1
    12 4
    13 9
    14 2
    15 10
    16 4
    17 15
    18 10
    19 5
    20 0
    21 16
    22 12
    23 8
    24 4
    25 0
    26 22
    27 19
    28 16
    29 13
    30 10
    31 7
    32 4
    33 1
    34 32
    35 30
    36 28
    37 26
    38 24
    39 22
    40 20
    41 18
    42 16
    43 14
    44 12
    45 10
    46 8
    47 6
    48 4
    49 2
    50 0
    51 49
    52 48
    53 47
    54 46
    55 45
    56 44
    57 43
    58 42
    59 41
    60 40
    61 39
    62 38
    63 37
    64 36
    65 35
    66 34
    67 33
    68 32
    69 31
    70 30
    71 29
    72 28
    73 27
    74 26
    75 25
    76 24
    77 23
    78 22
    79 21
    80 20
    81 19
    82 18
    83 17
    84 16
    85 15
    86 14
    87 13
    88 12
    89 11
    90 10
    91 9
    92 8
    93 7
    94 6
    95 5
    96 4
    97 3
    98 2
    99 1
    100 0
    

    这个表就是100%(1--n)的每一步结果
    注意51-100,34-50,26-33
    hhh_
    等差数列熟不熟悉?
    发现在[k/2]+1到k这个区间里,k%i是一个等差数列,公差为1
    在[k/3]+1到[k/2]这个区间里,k%i也是一个等差数列,公差为2
    在[k/4]+1到[k/3]这个区间里,k%i也是一个等差数列,公差为3
    .........
    一直到[k/√k]+1到[k/(√k-1)]这个区间里,k%i也是一个等差数列,公差为(√k-1).
    剩下的1到[k/√k]的区间直接暴力求解即可.
    再特殊处理一下n<k的情况,比如n99,k100可以自己想象一下

    那么上代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    long long n,i,k,l,ans;
    int main(){
        cin>>n>>k;
        if(n>=k)
            ans=(n-k)*k;
        else{
            for(i=1;i*i<=k&&i<n;i++){
                if(k/i<n){l=k/i;break;}
                l=i;
            }
            l++;
            ans=(n-l+1)*(k%n+k/l*(n-l)+k%n)/2;
        }
        for(i=k/n+1;i*i<=k;i++)
            ans+=(k%i+i*(k/i-k/(i+1)-1)+k%i)*(k/i-k/(i+1))/2;
        n=k/i;
        for(int i=1;i<=n;i++)
            ans+=k%i;
        cout<<ans;
        return 0;
    }
    

    完了,不懂的评论问吧

  • 相关阅读:
    备份的数据库存儲過程
    用反射调用任意.net库中的方法
    基于.NET的多线程编程入门
    手写分页函数C#
    .net中的泛型
    prototype.js开发笔记
    此方法用于确认用户输入的不是恶意信息
    利用DataSet、DataTable、DataView按照自定义条件过滤数据
    读取文件列表
    注册客户端脚本
  • 原文地址:https://www.cnblogs.com/lisuier/p/9609502.html
Copyright © 2011-2022 走看看