总时间限制: 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;
}
小结:
很多题目都不能用常规的方法解决,遇到这种情况,应仔细分析样例,找到方法。