2020牛客暑期多校训练营(第七场)H题Dividing(整除分块法)

2020牛客暑期多校训练营(第七场)H题Dividing(整除分块法)

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
",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
",now,to,ans,i);
	}
	printf("%lld
",(ans+k+n-1)%mod);
}

原文地址:https://www.cnblogs.com/whitelily/p/13418093.html