1. 程式人生 > 實用技巧 >2020牛客暑期多校訓練營(第七場)H題Dividing(整除分塊法)

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\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);
}