2020牛客暑期多校训练营(第七场)H题Dividing(整除分块法)
2020牛客暑期多校训练营(第七场)H题Dividing(整除分块法)
题意:给一个N,K,首先对于所有1,k(1<=k<=K),都是符合要求的,然后所有的符合要求的数的数(n,k),若n+k<N,则(n+k,k)也是好的,若nk<N,则(nk,k)也是好的,求符合要求的数量。
题解:首先可以先写一写,举个栗子,(1,3)。
可以变为(4,3),(3,3)。
现在应该很容易发现,乘法操作已经没用了,因为乘3必然是3的倍数,一定可以通过加3到达,所以可以写成两个不等式。
1+m*k<=N,
m*k<=N,
m表示符合要求的个数,然后暴力枚举k,算出每个m既可,K过大枚举超时,但是我们可以发现k中间有很多的m都相等,呈线性关系,故可用整除分块优化。
#include<iostream>
#define ll long long
using namespace std;
const ll mod=1e9+7;
ll n,k,ans,m,to,now;
int main(){
scanf("%lld%lld",&n,&k);
for(ll i=2;i<=k;i++){
now=i;
m=n/i;
if(m==0)break;
to=min(n/m,k);
i=to;
m%=mod;
to%=mod;
ans=(ans+m*(to-now+1))%mod;
//printf("%lld %lld %lld %lld\n",now,to,ans,i);
}
for(ll i=2;i<=k;i++){
now=i;
m=(n-1)/i;
if(m==0)break;
to=min((n-1)/m,k);
i=to;
m%=mod;
to%=mod;
ans=(ans+m*(to-now+1))%mod;
//printf("%lld %lld %lld i=%lld\n",now,to,ans,i);
}
printf("%lld\n",(ans+k+n-1)%mod);
}