整除分块 (+例题变形K-取模 2022年天梯赛(GPLT)上海理工大学校内选拔赛)

整除分块

K-取模 2022年中国高校计算机大赛-团队程序设计天梯赛(GPLT)上海理工大学校内选拔赛

这本是一道取模的题目,运用数学公式转换,便可以用整除分块解决。


先介绍一下整除分块

以20为例,一共出现了多少个i的倍数?

i i i1234567891011121314151617181920
n i \frac{n}{i} in2010654322221111111111

可以发现在连续的一段区间内是相同的,那么就启发我们是否可以将其分为若干块分别进行计算呢?

这就是整除分块的核心思想了。

n/i 表示n里面出现了几个 i 的倍数。
也就是在n个里面,每i个为一组,可以分n/i 组,每组里有一个i的倍数

当然会有剩余的。

如果再用 n 除以 n/i ,便是如果分为 n/i 组,那么每组应该有 n/(n/i) =x 个
注意:每次都是向下取整

即x个数字为一组,会有 n/i组(当然也有剩余),也就是这x个都至少有 n/i个倍数

那么区间【i,x】,倍数皆为 n/i

总结:

利用除法的性质,将问题分解为若干个块,每个块内的值相同,从而减少计算量。整除分块在解决一些数学问题时非常有效,特别是当问题涉及到大量除法操作时,它可以大大减少计算时间。

题意

计算 ∑ i = 1 n ( n % i ) \sum_{i=1}^{n}{(n\%i)} i=1n(n%i)

因为答案可能很大,因此只需要输出答案需要对998244353取模后的结果

思路

赛时一直从规律入手,打表,废了太长时间。应该从变化数学公式、整除分块入手。

且看以下推导(懒得用latex):

请添加图片描述

代码

void solve()
{
    int n,ans=0;
    cin>>n;
    ans=(n%mod)*(n%mod)%mod;//n^2
    __int128 i=1,j=1;//区间和会超longlong,int128最大值最高位2^127-1,不会溢出
    while(i<=n)
    {
        j=min ((__int128)n,n/(n/i));
        ans=(ans-((i+j)*(j-i+1)/2%mod*((n/i)%mod)%mod)+mod)%mod;//多取模
        i=j+1;
    }
    cout<<ans<<'\n';
}

感谢亓boyan的整除分块启蒙

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值