余数之和

总时间限制: 1000ms 内存限制: 65536kB
描述
给定两个数:n和m
计算出:n%1+n%2+…+n%m的结果。(结果对10^9+7取模)

输入
第1行:两个整数n和m

输出
第1行:整数S(对10^9+7取模后的结果)

样例输入

3 4

样例输出

4

【数据规模与说明】
1≤n,m≤10^9

分析

此题n,m均小于10的9次方,如果一一计算肯定超时,所以此题必须优化,找出方法
假设n=10,m=15 
n%1到m的余数分别为:0,0,1,2,0,4,3,2,1,0,10,10,10,10,10; 
观察发现4,3,2,1,0; 2,0 均为等差数列;
继续推下去,发现10/6=1,10/7=1,10/8=1,10/9=1,10/10=1;
6和10刚好是等差数列的头和尾; 
所以找到n/m得数相同的头和尾就找到了等差数列的头和尾

正确代码如下:

#include<cstdio>
long long n,m,sum,y=1000000000+7;   //n,m均小于10的9次方,int装得下,但sum可能装不下,所以全用long long
long long maxn;
int main()
{
    scanf("%lld %lld",&n,&m);       
    if(n<m)                     //如果n<m,n%m一定等于n,为了节省时间,可以单独处理  
    {
        sum+=(m-n)*n;           
        m=n;                                
    }
    for(long long i=1;i<=m;i++)             //利用结论
    {
        maxn=n/(n/i);                       //算出等差数列末尾 
        if(maxn>m) maxn=m;                  //如果末尾超过边界,则只能算到边界 
        sum+=(n%maxn+n%i)*(maxn-i+1)/2;     //利用等差数列公式算出结果累加到sum 
        i=maxn;                             //将i的值赋为maxn,避免重复   
    }
    printf("%lld",sum%y);               //n,m小于10的9次方,假设每次取模后结果为10的9次方,sum最大值为10的18次方,装得下,所以可以最后再取模 
    return 0;
}

小结:
很多题目都不能用常规的方法解决,遇到这种情况,应仔细分析样例,找到方法。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值