【BZOJ】3930: [CQOI2015]选数

题意

从区间\([L, R]\)\(N\)个数(可以重复),问这\(N\)个数的最大公约数是\(K\)的方案数。(\(1 \le N, K \le 10^9, 1 \le L \le R \le 10^9, H-L \le 10^5\)

分析

好神的题。注意\(H-L \le 10^5\)这个条件,则假设\(N\)个数不全相同,那么他们的最大公约数小于最大和最小的两个数之差,证明很简单,设\(d\)为最大公约数,则\(dk_2 -dk_1 = d( k_2 - k_1 ) > d\)

题解

因此我们可以先算出\(N\)个数不全相同的方案数,然后再特判一下全相同的情况,加起来就是答案了。
计算前者我们可以将边界除以\(K\),然后在新边界里面找最大公约数为\(1\)的方案数。由于新边界最大于最小之差不超过\(10^5\),因此我们暴力枚举一下这些公约数,用容斥剪掉重复的即可。也就是说:

\[d_i = sum - \sum_{i|j} d_j \]

\(sum\)的计算注意剪掉\(N\)个数相同的方案。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mo=1000000007;
int ipow(int a, int b) {
	int x=1;
	a%=mo;
	for(; b; b>>=1, a=(ll)a*a%mo)
		if(b&1) x=(ll)x*a%mo;
	return x;
}
int d[100005];
int main() {
	int N, K, L, R, MX, flag=0;
	scanf("%d%d%d%d", &N, &K, &L, &R);
	if(L<=K && K<=R) flag=1;
	L=(L-1)/K, R=R/K;
	MX=R-L;
	for(int i=MX; i>=1; --i) {
		int &now=d[i];
		ll l=L/i, r=R/i, t=r-l;
		if(l<r) {
			now=(ipow((t), N)-t+mo)%mo;
			for(int j=i<<1; j<=MX; j+=i) now=(now-d[j]+mo)%mo;
		}
	}
	printf("%d\n", d[1]+flag);
	return 0;
}
posted @ 2015-11-22 17:52  iwtwiioi  阅读(1122)  评论(0编辑  收藏  举报