【CodeForces】【数学】616E-Sum of Remainders

8 篇文章 1 订阅
6 篇文章 0 订阅

CodeForces 616E Sum of Remainders

题目

◇题目传送门◆

题目大意

给定 n,m n , m mi=1(nmodi) ∑ i = 1 m ( n mod i )

思路

暴力??? 1013 10 13 ,早就炸了。。。

我们就用数学方法分析一下:

Step1.变模为求和

众所周知, nmodi n mod i 是与 nini n − i ⋅ ⌊ n i ⌋ 等价的,不信可以找几个数算一算。

S=mi=1(nmodi) S = ∑ i = 1 m ( n mod i ) ,不难推出 S=nmmi=1ini S = n ⋅ m − ∑ i = 1 m i ⋅ ⌊ n i ⌋ 。所以,我们成功地将模运算转化为了求和运算。

Step2. 1013 10 13

nm n ⋅ m 的计算对于我们来说是极其容易的,难点就是后面的那个 mi=1ini ∑ i = 1 m i ⋅ ⌊ n i ⌋

作为一个在数学世界里搞了N年事情的大佬,经验能够告诉我: ni ⌊ n i ⌋ 的结果有些是一样的,于是区间 [1,m] [ 1 , m ] 就被分成了许多个具有不同 ni ⌊ n i ⌋ 的值所构成的区间。

不明白?举个例子:令 n=18 n = 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 (废话)

我们设区间 i i 的开头为li,结尾为 ri r i ,不难得出递推式:

li=ri1+1ri=nni l i = r i − 1 + 1 r i = n ⌊ n i ⌋

边界条件就是 l1=1,r1=1 l 1 = 1 , r 1 = 1

Step4.计算答案

终于到了激动人心的时刻了!

我们由上面三步可得,区间 [li,ri] [ l i , r i ] 是一个等差数列,所以对于这个区间,答案应减去:

xi(rili+1)(li+ri)2 x i ⋅ ( r i − l i + 1 ) ⋅ ( l i + r i ) 2

其中 xi=ni x i = n i

实现细节

注意应边模边计算。

正解代码

#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 LOACL
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
    #endif
    scanf("%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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值