CodeForces 616E Sum of Remainders
题目
◇题目传送门◆
题目大意
给定n,mn,m求∑mi=1(nmodi)∑i=1m(nmodi)。
思路
暴力???10131013,早就炸了。。。
我们就用数学方法分析一下:
Step1.变模为求和
众所周知,nmodinmodi是与n?i??ni?n?i??ni?等价的,不信可以找几个数算一算。
记S=∑mi=1(nmodi)S=∑i=1m(nmodi),不难推出S=n?m?∑mi=1i??ni?S=n?m?∑i=1mi??ni?。所以,我们成功地将模运算转化为了求和运算。
Step2.10131013?
n?mn?m的计算对于我们来说是极其容易的,难点就是后面的那个∑mi=1i??ni?∑i=1mi??ni?。
作为一个在数学世界里搞了N年事情的大佬,经验能够告诉我:?ni??ni?的结果有些是一样的,于是区间[1,m][1,m]就被分成了许多个具有不同?ni??ni?的值所构成的区间。
不明白?举个例子:令n=18n=18
很容易发现,区间[1,18][1,18]被分为了[1,1],[2,2],[3,3],[4,4],[5,6],[7,9],[10,18][1,1],[2,2],[3,3],[4,4],[5,6],[7,9],[10,18]七个区间,而这七个区间都可以使用等差数列求出和。
Step3.计算区间??
我们容易发现,每个区间的开始就是上一个区间的结束+1 (废话)。
我们设区间ii的开头为 ,结尾为riri,不难得出递推式:
边界条件就是 l1=1,r1=1l1=1,r1=1 。
Step4.计算答案
终于到了激动人心的时刻了!
我们由上面三步可得,区间[li,ri][li,ri]是一个等差数列,所以对于这个区间,答案应减去:
其中 xi=nixi=ni 。
实现细节
注意应边模边计算。
正解代码
#include<cstdio>
#include<algorithm>
using namespace std;typedef long long ll;
const int Mod=1e9+7;ll N,M;ll GetSum(ll x) {
//等差数列return (x%Mod)*((x+1)%Mod)/2%Mod;
}
ll Sum(ll l,ll r) {return GetSum(j)-GetSum(i-1);
}ll ModAdd(ll x,ll y) {return (x%Mod+y%Mod)%Mod;
}
void ModSub(ll &ans,ll i,ll j,ll x) {ans=ModAdd(ans,Mod-Sum(j,i-1)*x%Mod);
}int main() { #ifdef LOACLfreopen("in.txt","r",stdin);freopen("out.txt","w",stdout);#endifscanf("%lld %lld",&N,&M);ll ans=(N%Mod)*(M%Mod)%Mod;M=min(N,M);//当N>i时,x=0,不需要再算for(ll i=1,j,x;i<=M;i=j+1) {x=N/i;j=min(N/max(x,1*1LL),M);ModSub(ans,i,j,x);}printf("%lld\n",ans);return 0;
}