bzoj 1257 洛谷 P2261 [CQOI2007]余数求和 分块+数学

题目描述
给出正整数n和k,计算G(n, k)=k mod 1 + k mod 2 + k mod 3 + … + k mod n的值,其中k mod i表示k除以i的余数。例如G(10, 5)=5 mod 1 + 5 mod 2 + 5 mod 3 + 5 mod 4 + 5 mod 5 …… + 5 mod 10=0+1+2+1+0+5+5+5+5+5=29
输入输出格式
输入格式:

两个整数n k

输出格式:

答案

输入输出样例
输入样例#1:
10 5
输出样例#1:
29
说明
30%: n,k <= 1000
60%: n,k <= 10^6
100% n,k <= 10^9

分析:题目相当于求sum(k%i) (1<=i<=n)
显然可以化成k-k/i*i (/表示整除)。
所以,显然可以求n*k-k/i*i。显然n*k已知,就是求后面那个了。显然k/i有重复,只有sqrt(n)个值,因为k/2+1到k都是1,k/3+1到k/2都是2。两种方法,一种暴力sqrt(n)个值。另一种可以把k/sqrt(k)到k搞掉,剩下sqrt(k)暴力for,都能解决。复杂度都是O(sqrt(n))。

代码:

#include <iostream>
#include <cstdio>
#include <cmath>

using namespace std;

long long n,k,block,ans,i,l,r;

int main()
{
    scanf("%lld%lld",&n,&k);
    ans=n*k;    
    block=trunc(sqrt(n));   
    for (i=1;i<=block;i++)
    {
        l=k/(i+1)+1;
        if (l>n) continue; 
        r=min(k/i,n);
        ans-=i*(l+r)*(r-l+1)/2;
    }
    for (i=1;i<=min(k/(block+1),n);i++)
    {
        ans-=(k/i)*i;
    }
    printf("%lld",ans);
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值