Ice Rain(数论+分段思想)

Ice Rain

 Ice Rain------I was waiting for a girl, or waiting for been addicted to the bitter sea. Love for irrigation in silence. No one considered whether the flowers came out or wither. Love which I am not sure swing left and right. I had no choice but to put my sadness into my heart deeply.

   Yifenfei was waiting for a girl come out, but never.
His love is caught by Lemon Demon. So yifenfei ’s heart is “Da Xue Fen Fei” like his name.
The weather is cold. Ice as quickly as rain dropped. Lemon said to yifenfei, if he can solve his problem which is to calculate the value of , he will release his love.
Unluckily, yifenfei was bored with Number Theory problem, now you, with intelligent, please help him to find yifenfei’s First Love.

Input
Given two integers n, k(1 <= n, k <= 10 9).
Output
For each n and k, print Ice(n, k) in a single line.
Sample Input

5 4
5 3

Sample Output

5
7
题意:

让我们求 ni=1k%i ∑ i = 1 n k % i

分析:

首先对于一个k%i的值我们可以根据

k=i×t+r k = i × t + r

其中i是取模的数,t是商,r便是k%i这个余数

因此我们有

k % i=r=ki×t k   %   i = r = k − i × t

所以

ni=1k%i=ni=1(ki×t)=knni=1i×ki ∑ i = 1 n k % i = ∑ i = 1 n ( k − i × t ) = k n − ∑ i = 1 n i × ⌊ k i ⌋

所以我们的问题转换成了求

ni=1i×ki=1×k1+2×k2+...+n×kn ∑ i = 1 n i × ⌊ k i ⌋ = 1 × ⌊ k 1 ⌋ + 2 × ⌊ k 2 ⌋ + . . . + n × ⌊ k n ⌋

根据向下取整,我们知道 k1kn ⌊ k 1 ⌋ 到 ⌊ k n ⌋ 中一定可以分成一段一段连续的等值区间( kikj ⌊ k i ⌋ 到 ⌊ k j ⌋ ),当然了区间最小长度为1,也就是就一个这样的值(比如 43=1,44=1 4 3 = 1 , 4 4 = 1

对于某些区间来说区间长度可能很庞大,这样当我们碰到第一个i使得 ki=d ⌊ k i ⌋ = d 时,如果我们能得到区间的最后一个编号j( kj=d ⌊ k j ⌋ = d )那么我们就可以直接将d提出来,剩下的部分用等差数列求和公式算,大大增加了效率。

d=ki,j=kd d = k i , j = k d 那么j就是我们要求的最后一个满足要求的位置
因此下次直接可以跳到j+1位置

证明:
已知 ki=d k i = d ,我们要求得一个j使得区间[i,j]之间的每个数 l l kl=d
那么令 j=kd j = k d ,肯定可以使得区间[i,j]内的数满足性质,但是它是不是最后一个呢?
假设令 kj+1=d k j + 1 = d
d(j+1)k d ⋅ ( j + 1 ) ≤ k
根据 kd=j k d = j
可以得到 k(d×j)<d k − ( d × j ) < d
k<d(j+1) k < d ⋅ ( j + 1 )
矛盾,因此j是最大的

而且根据式子

ni=1i×ki=1×k1+2×k2+...+n×kn ∑ i = 1 n i × ⌊ k i ⌋ = 1 × ⌊ k 1 ⌋ + 2 × ⌊ k 2 ⌋ + . . . + n × ⌊ k n ⌋

我们可以知道当n>k之后就变成0了,所以我们只需要求出小于等于n的即可

code:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n,k;
int main(){
    while(scanf("%lld%lld",&n,&k) != EOF){
        ll ans = n * k;
        if(n > k) n = k;
        for(ll i = 1; i <= n;){
            ll d = k / i;
            ll j = k / d;
            if(j > n) j = n;
            ans = ans - d * ((j - i + 1) * (i + j) / 2);//这里等比数列求和公式相当于a1 = i,通项是j,公比为1,个数j-i+1个
            i = j + 1;
        }
        printf("%lld\n",ans);
    }
    return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值