对于一类题目及其中间过程需要计算的结果,那么我们可以引入一类算法:整除分块。对于一个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;
}
例题
求
依旧对答案分块
#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;
}
变式
求
做一步转化,k mod i=k-(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)
*/
完结撒花