整除分块入门

对于一类题目及其中间过程需要计算\sum_{i=1}^{n}n/i的结果,那么我们可以引入一类算法:整除分块。对于一个n来说,除以n所得的结果个数是不超过sqrt(n)量级的。

所以我们可以计算出当前结果所对应的最小的i与最大的i,定义其为L,R,则每次L=R'+1,R=N/(N/L)

代码:

#include<bits/stdc++.h>
#define endl '\n'
#define ll long long
using namespace std;
const int maxn=1e5+10;
const int mod=1e9+7;
ll n,a,b,ans;
int main(){
	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
	cin>>n;
	ll l=1,r;
	while(1){
	    if(l>n) break;
	    r=n/(n/l);
	    ans+=(r-l+1)*(n/l);
	    ans%=mod;
	    l=r+1;
	}
	cout<<ans<<endl;
	return 0;
}

例题

\sum_{i=1}^{n} n/(a*i+b)  mod  10^9+7 

依旧对答案分块

#include<bits/stdc++.h>
#define endl '\n'
#define ll long long
using namespace std;
const int maxn=1e5+10;
ll n,a,b;
int main(){
	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
	cin>>n>>a>>b;
	ll l=1;
	if(a*l+b>n){cout<<0<<endl;return 0;}
    ll r=(n/(n/(a*l+b))-b)/a,ans=0;
	while(1){
	    ans+=(r-l+1)*(n/(a*l+b));
	    ans%=int(1e9+7);
	    l=r+1;
	    if(l>n||a*l+b>n) break;
	    r=(n/(n/(a*l+b))-b)/a;
	    r=min(r,n);
	}
	cout<<ans<<endl;
	return 0;
}

变式

\sum_{i=1}^{n} k mod i

做一步转化,k mod i=k-(k/i)*i,那么就是求n*k-\sum_{i=1}^{n}(k/i)*i,注意n>k的情况

代码:

#include<bits/stdc++.h>
#define ll long long
#define endl '\n'
#define pii pair<int,int> 
using namespace std;
ll n,k,ans;
int main(){
	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
	cin>>n>>k;ans=n*k;
	for(ll i=1,j=1;i<=n;i=j+1){
		ll p=k/i;
		j=p?min(k/p,n):n;
		ans-=(i+j)*(j-i+1)*p/2;
	} 
	cout<<ans<<endl;
	return 0;
}
/*
k-i*(k/i)
*/

完结撒花

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值