【分块】BZOJ 1257 [CQOI2007]余数之和sum题解

(传送门)

题目大意

ni=1k mod i ,n,k<=1013

解题分析

这道题的被除数不变,然后除数是依次加1,直觉就是余数是有规律的,事实上也确实有规律。

a=k/i (整除运算),则 k mod i=kai

那么对于接下来的i+1,假设 a=k/(i+1) (i+1和i被k除的整数部分相同),有 k mod (i+1)=ka(i+1)=kaia=k mod ia

然后对于i+2,如果被k除的整数部分与i+1相同,那么很明显 k mod (i+2)=k mod i2a

这里就会发现,如果对于一个区间[i,j],他们被k除的商的整数部分a相同,那么他们的余数可以构成一个公差为a的等差数列,所以这样的话可以枚举整数部分a,然后找出被k出后整数为a的最小值和最大值,并直接求出他俩的余数,然后套进等差数列公式就行了。

注意,在1-sqrt(n)范围内的商a是各不相同的,所以这里有分块的思想:1-sqrt(n)直接求,然后a范围也是1-sqrt(n),套等差数列(这道题算数论嘛???),大于k的直接ans+=k。

时间:O( sqrt(n) ); 空间:O(1);

#include<cmath>
#include<cstdio>
#define LL long long
LL n,m,ans; int k;
using namespace std;
int main()
{
    freopen("remainders.in","r",stdin);
    freopen("remainders.out","w",stdout);
    scanf("%lld%lld",&m,&n); k=sqrt(n); ans=0;
    if (m>n) {ans+=(m-n)*n; m=n;}
    for (int i=2;i<=k&&i<=m;i++) ans+=n%i;
    for (int i=1;i<=k&&m>k;i++){
        LL L=n/(i+1)+1,R=n/i,tema,temb;
        if (L<k+1) L=k+1; if (R>m) R=m; if (L>R) continue;
        tema=n%L; temb=n%R; ans+=(tema+temb)*(R-L+1)/2;
    }
    printf("%lld",ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值