Sum of Remainders
◇题意◇
给定 ,求
断绝一切念想对吧
◇解析◇
做前内心戏
(模求和??)&&(1e13)
模求和,难道需要我不会的运算定律???我强大的算术基本定理可不是瞎吹的!暴力吧?!
不对不对,肯定是我看错了,擦眼睛再看一遍:
对对对对对,你没有看错,就是 ;
“断绝一切念想”。
对,这就是想更优算法的理由!
严肃的分析
Ⅰ.模求和
对于一个可以说在编程路途中给我们无数麻烦的算术钉子户“
”大爷来说,在各种题目中躺在
道路上挡道是再平常不过的了,因此处理“
”是看完题的第一想法。处理成什么呢???这时,我们的老熟人“
”“
”在路上打了个招呼,于是,我们坚定地绕路走:
Ⅱ.1e13
(Ⅰ)中的分析乍一眼看很有道理,当我考试想出来这些时我以为我能
,但抹了眼睛再看
!!
完全没有解决啊!!!
不能放弃啊,我们把注意力集中到
的表达式上。
显然是容易算的,因此:有一定计算难度的是后面的
多年计算的经验告诉我们 中有许多值是一样的,而拥有相同商的 也应该是连续的,于是 构成了由许多个具有不同 值的区间组成的大区间
这样我们就把6次计算收缩到4个可利用等差数列求和公式和乘法计算的区间,进行有效的收缩,而当 更大,收缩效果会更明显
Ⅲ.寻找区间
感觉已经距
很近了!(真的是这样吗)
注意上图中每一段区间的开始和结束
——
——
——
(如果
则
)
很容易的发现所有的区间构成一个连续的数列,即
换句话说,就是当前区间的起点就是上一个的结尾+1(这不是废话吗)
关于找结尾我们有很多种算法
⑴显然是
的因数(从小到大),不好写且不优;
⑵设区间
开头为
,结尾
显然 ,所以 就可以完美的递推表达出来了。
最后一个区间结尾是 ,不要写得陶醉停不下来
Ⅳ.计算答案
根据上文定义,对于
所有值中有相同
(下取整过后的商)
开始时
对于这段区间 应该减去
干完所有的区间,就ok了
◇代码◇
#include<cstdio>
#include<algorithm>
using namespace std;
const int Mod=int(1e9)+7;
#define LL long long
LL n,m;
LL ans,l=1,r,x;
LL dcsl(LL x) {
return (x%Mod)*((x+1)%Mod)/2%Mod;
}
LL Dcsl(LL i,LL j) {
return dcsl(j)-dcsl(i-1);
}
LL Add(LL x,LL y) {
return ((x%Mod)+(y%Mod))%Mod;
}
LL Sub() {
ans=Add(ans,Mod-(x*(Dcsl(l,r)))%Mod);
}
int main()
{
scanf("%lld%lld",&n,&m);
ans=((n%Mod)*(m%Mod))%Mod;
m=min(m,n);
//当n>i,x=0,没必要再算
for(;l<=m;l=r+1) {
x=n/l;
r=min(m,n/x);
Sub();
}
printf("%lld",ans);
}
再说两句
1.
才是最骚的。
2.第二句。