洛谷 P3172 :[CQOI2015]选数(莫比乌斯反演 + 杜教筛)

洛谷 P3172 :[CQOI2015]选数(莫比乌斯反演 + 杜教筛)_第1张图片


∑ i 1 = 1 h ∑ i 2 = 1 h ∑ i 3 = 1 h . . . [ g c d ( i 1 , i 2 , i 3 , . . ) = k ] \sum_{i_1 = 1}^h\sum_{i_2 = 1}^h\sum_{i_3 = 1}^h...[gcd(i_1,i_2,i_3,..) = k] i1=1hi2=1hi3=1h...[gcd(i1,i2,i3,..)=k] = ∑ i 1 = 1 ⌊ h k ⌋ ∑ i 2 = 1 ⌊ h k ⌋ ∑ i 3 = 1 ⌊ h k ⌋ . . . [ g c d ( i 1 , i 2 , i 3 , . . ) = 1 ] =\sum_{i_1 = 1}^{\lfloor\frac{h}{k}\rfloor}\sum_{i_2 = 1}^{\lfloor\frac{h}{k}\rfloor}\sum_{i_3 = 1}^{\lfloor\frac{h}{k}\rfloor}...[gcd(i_1,i_2,i_3,..) = 1] =i1=1khi2=1khi3=1kh...[gcd(i1,i2,i3,..)=1] = ∑ p = 1 ⌊ h k ⌋ μ ( p ) ∑ i 1 = 1 ⌊ h k ∗ p ⌋ ∑ i 2 = 1 ⌊ h k ∗ p ⌋ ∑ i 3 = 1 ⌊ h k ∗ p ⌋ . . . =\sum_{p = 1}^{\lfloor\frac{h}{k}\rfloor}\mu(p)\sum_{i_1 = 1}^{\lfloor\frac{h}{k*p}\rfloor}\sum_{i_2 = 1}^{\lfloor\frac{h}{k*p}\rfloor}\sum_{i_3 = 1}^{\lfloor\frac{h}{k*p}\rfloor}... =p=1khμ(p)i1=1kphi2=1kphi3=1kph... = ∑ p = 1 ⌊ h k ⌋ μ ( p ) ∗ ( ⌊ h k ∗ p ⌋ − ⌊ l − 1 k ∗ p ⌋ ) n =\sum_{p = 1}^{\lfloor\frac{h}{k}\rfloor}\mu(p) *(\lfloor\frac{h}{k * p}\rfloor - \lfloor\frac{ l - 1}{k * p}\rfloor)^n =p=1khμ(p)(kphkpl1)n

右边可以分块,需要预处理 μ ( i ) \mu(i) μ(i)的前缀和,由于 上限达到了 1 0 9 10^9 109,上杜教筛


#include
using namespace std;
const int maxn = 1e6 + 10;
const int mod = 1e9 + 7;
typedef long long ll;
bool ispri[maxn];
int pri[maxn],mu[maxn];
int sum[maxn];
map<int,int> mp;
int n,k,l,h;
inline int read(){
    int x=0,f=1; char ch=getchar();
    for (;ch<'0'||ch>'9';ch=getchar())  if (ch=='-')    f=-1;
    for (;ch>='0'&&ch<='9';ch=getchar())    x=(x<<3)+(x<<1)+ch-'0';
    return x*f;
}
void sieve(int n) {
	ispri[0] = ispri[1] = true;
	pri[0] = 0;mu[1] = 1;
	for(int i = 2; i <= n; i++) {
		if(!ispri[i]) pri[++pri[0]] = i,mu[i] = -1;
		for(int j = 1; j <= pri[0] && i * pri[j] <= n; j++) {
			ispri[i * pri[j]] = true;
			if(i % pri[j] == 0) break;
			mu[i * pri[j]] = -mu[i];
		}
	}
	sum[0] = 0;
	for(int i = 1; i <= n; i++)
		sum[i] = (sum[i - 1] + mu[i]) % mod;
}
int getsum(int x) {
	if(x <= maxn - 10) return sum[x];
	if(mp[x]) return mp[x];
	int res = 1;
	int i,j;
	for(i = 2; i <= x; i = j + 1) {
		j = x / (x / i);
		res = (res - 1ll * (j - i + 1) * getsum(x / i) % mod + mod) % mod;
	}
	return mp[x] = res;
}
int fpow(int a,int b) {
	int r = 1;
	while(b) {
		if(b & 1) r = 1ll * r * a % mod;
		a = 1ll * a * a % mod;
		b >>= 1;
	}
	return r;
}
int main() {
	sieve(maxn - 10);	
	n = read();k = read();l = read();h = read();
	h = h / k;
	l = (l - 1) / k;
	int i,j;
	int ans = 0;
	for(i = 1; i <= h; i = j + 1) {
		if(i <= l) j = min(h / (h / i),l / (l / i));
		else j = h / (h / i);
		int tmp = fpow((h / i - l / i + mod) % mod,n);
		ans = (ans + 1ll * ((getsum(j) - getsum(i - 1) + mod) % mod) * tmp % mod) % mod;	
	}
	printf("%d\n",ans);
	return 0;
}

你可能感兴趣的:(莫比乌斯反演,莫比乌斯函数,杜教筛)