整除分块

例题1

  ∑ 1 n n i   , n < = 1 0 12 . \ \sum_1^n \frac{n}{i}\,,n<=10^{12}.  1ninn<=1012.

题目链接.
数据范围小跑o(n)当然没问题,数据范围这么大就要另想办法。
打表观察下,设n=20
1 2 3 4 5 6 7 8 9 10 11 12 13…20
20 10 6 5 4 3 2 2 2 2 1 1 1 1
我们发现n/i的值有某些段是重复的数字。
n i = k \frac{n}{i}=k in=k,
n = k ∗ i + d , 0 < = d < i n=k*i+d, 0<=d<i n=ki+d,0<=d<i
那么 n i + d = k \frac{n}{i+d}=k i+dn=k
i + d = n k = n n i i+d=\frac{n}{k}=\frac{n}{\frac{n}{i}} i+d=kn=inn
那么i和i+d的取值就是相同的。我们找出这一段即可。
也就是我们要找出最接近n的 i ∗ k = n i*k=n ik=n,假设i<k,则i有 n \sqrt n n 个,i和k共有 2 ∗ n 2*\sqrt n 2n 个。
我们设一个段的左端点为 l l l,则右端点 r = n n l r=\frac{n}{\frac{n}{l}} r=lnn.这一段的取值都为 n l \frac{n}{l} ln,因此总值为: ( r − l + 1 ) ∗ n l (r-l+1)*\frac{n}{l} (rl+1)ln
参考代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n,ans;
int main() {
	cin>>n;
	for(ll l=1,r; l<=n; l=r+1) {
		r=n/(n/l);
		ans+=(r-l+1)*(n/l);
	}
	cout<<ans<<endl;
}

例题2

P2261 [CQOI2007]余数求和$

  ∑ 1 n n % i   , n < = 1 0 12 . \ \sum_1^n n \%i\,,n<=10^{12}.  1nn%in<=1012.
n % i = n − n i ∗ i n\%i=n-\frac n i*i n%i=nini
  ∑ 1 n n % i = ∑ 1 n ( n − n i ∗ i ) \ \sum_1^n n \%i=\sum_1^n(n-\frac n i*i)  1nn%i=1n(nini)
= n ∗ n − ∑ 1 n ( n i ∗ i ) =n*n-\sum_1^n(\frac n i*i) =nn1n(ini)
需要求: ∑ 1 n ( n i ∗ i ) \sum_1^n(\frac n i*i) 1n(ini)
分段后,对每段的n/i是定值k,则这段就是ki,k(i+1)…
每段的总值为:
( r − l + 1 ) ∗ n l ∗ l + r 2 (r-l+1)*\frac{n}{l}*\frac{l+r}2 (rl+1)ln2l+r
代码也放上吧。

#include<cstdio>
#include<algorithm>
#include<iostream>
using namespace std;
typedef long long ll;

int main() {
    ll n,k;
    scanf("%lld%lld",&n,&k);//30/8=3,,30/x=3,x=30/3=10;=>8...10为一个区间。 
    ll ans=n*k;
   
    for(ll l=1,r;l<=n;l=r+1) {
        if(k/l!=0) r=min(k/(k/l),n); 
        else r=n;
        ans-=(k/l)*(r-l+1)*(l+r)/2;
       
    }
    printf("%lld",ans);
    return 0;
}

P2260 [清华集训2012]模积和

这个题目懒得写了。推一堆式子。难点在于要会求 1 2 + 2 2 + 2 3 + . . . + n 2 1^2+2^2+2^3+...+n^2 12+22+23+...+n2的通项。
查资料的得:
∑ i = 1 n i 2 = n ∗ ( n + 1 ) ( 2 n + 1 ) 6 \sum_{i=1}^ni^2=\frac{n*(n+1)(2n+1)}6 i=1ni2=6n(n+1)(2n+1)
不写了,这么多公式,真麻烦。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值