[CQOI2015]选数-题解

版权声明:转载注明出处,谢谢,有问题可以向博主联系 https://blog.csdn.net/VictoryCzt/article/details/85090284

题目地址


题意简述

给定 N , K , L , H N,K,L,H 求下面式子在 m o d   1 0 9 + 7 {\rm mod\ 10^9+7} 意义下的值。

i 1 = L H i 2 = L H i N = L H [ g c d ( i 1 , i 2 ,   , i N ) = K ] \sum_{i_1=L}^H\sum_{i_2=L}^H\cdots\sum_{i_N=L}^H[gcd(i_1,i_2,\cdots,i_N)=K]

N , K 1 0 9 , 1 L H 1 0 9 , H L 1 0 5 N,K\leq 10^9 ,1\leq L\leq H\leq 10^9,H-L\leq10^5


通过莫比乌斯反演的套路,我们很容易将式子变成如下形式:
i 1 = L H K i N = L H K [ g c d ( i 1 ,   , i N ) = 1 ] \sum_{i_1=L}^{\lfloor\frac{H}{K}\rfloor}\cdots\sum_{i_N=L}^{\lfloor\frac{H}{K}\rfloor}[gcd(i_1,\cdots,i_N)=1]

然后将莫比乌斯函数套入,得到:

i 1 = L H K i N = L H K ( w i 1 , w i 2 , w i 3 ,   , w i N μ ( w ) ) = w = 1 H K μ ( w ) i 1 = L H K w i N = L H K w 1 = w = 1 H K μ ( w ) ( H K w L 1 K w ) N \sum_{i_1=L}^{\lfloor\frac{H}{K}\rfloor}\cdots\sum_{i_N=L}^{\lfloor\frac{H}{K}\rfloor}\left(\sum_{w|i_1,w|i_2,w|i_3,\cdots,w|i_N}\mu(w)\right) \\ =\sum_{w=1}^{\lfloor\frac{H}{K}\rfloor}\mu(w)\sum_{i_1=L}^{\lfloor\frac{H}{Kw}\rfloor}\cdots\sum_{i_N=L}^{\lfloor\frac{H}{Kw}\rfloor}1 \\=\sum_{w=1}^{\lfloor\frac{H}{K}\rfloor}\mu(w)\left(\frac{H}{Kw}-\frac{L-1}{Kw}\right)^N

我们用杜教筛筛前面的 μ \mu 的前缀和,后面分块算即可,复杂度 O ( n 2 3 ) O(n^{\frac{2}{3}})

代码~~

#include<map>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int M=2e6+10;
const ll Mod=1e9+7;
ll n,K,L,H,up;
ll prime[M],mu[M],cnt;
bool vis[M];
void init(){
	mu[1]=1;
	for(int i=2;i<=up;i++){
		if(!vis[i]){
			prime[++cnt]=i;
			mu[i]=Mod-1;
		}
		for(int j=1,v;j<=cnt&&i*prime[j]<=up;j++){
			v=i*prime[j];
			vis[v]=1;
			if(!(i%prime[j])){
				break;
			}
			mu[v]=(Mod-mu[i]);
		}
	}
	for(int i=2;i<=up;i++)mu[i]=(mu[i]+mu[i-1])%Mod;
}
ll fpow(ll a,ll b){
	ll res=1;
	for(;b;b>>=1,a=(a*a)%Mod)
		if(b&1)res=(res*a)%Mod;
	return res;
}
map <ll,ll> mp;
ll calc(ll x){
	if(x<=up) return mu[x];
	if(mp.count(x)) return mp[x];
	ll ans=1;
	for(ll i=2,j;i<=x;i=j+1){
		j=(x/(x/i));
		ans=(ans-((j-i+1)%Mod*calc(x/i)%Mod))%Mod;
	}
	if(ans<0)ans+=Mod;
	return mp[x]=ans;
}
ll solve(){
	up=min(H/K+1,M-1ll);
	init();
	ll Max=H/K,ans=0;
	ll t1=H/K,t2=(L-1)/K;
	for(ll i=1,j;i<=Max;i=j+1){
		if(t2/i)j=min(t1/(t1/i),t2/(t2/i));
		else j=t1/(t1/i);
		ans=(ans+(calc(j)-calc(i-1))%Mod*fpow((t1/i-t2/i),n)%Mod)%Mod;
	}
	if(ans<0)ans+=Mod;
	return ans;
}
int main(){
	scanf("%lld%lld%lld%lld",&n,&K,&L,&H);
	printf("%lld\n",solve());
	return 0;
} 

但是我们发现,题面上还有个 H L 1 0 5 H-L\leq10^5 的条件,由于在 L H L\sim H 中选一些不同的数出来的 g c d H L gcd\leq H-L ,那么就可以枚举 g c d gcd ,所以我们可以令 f [ i ] f[i] 为最大公约数为 i i 的答案。

关于为什么在 L H L\sim H 中选一些不同的数出来的 g c d gcd 不会大于 H L H-L ,这里简单证明:
首先我们只用考虑选两个数出来,如果这两个数的 g c d &gt; H L gcd&gt;H-L ,那么令小的那个为 g c d × k 1 gcd\times k_1 ,大的为 g c d × k 2 gcd\times k_2 ,那么由于它们两个不同,所以 k 2 k 1 1 k_2-k_1\geq 1 ,所以它们两个之间的距离一定大于了 H L H-L ,所以不可能同时在 L H L\sim H 内。

扫描二维码关注公众号,回复: 4566440 查看本文章

此时根据前面的转换,最后可以变成答案为 f [ 1 ] f[1]

下面我们考虑如何求取 f [ i ] f[i] :

我们从大到小枚举 i i ,我们可以发现,凡是为 i i 的倍数的数都有可能成为答案,所以先加上所有的 i i 的倍数组合后的结果 ( H K i L 1 K i ) N 1 × ( H K i L 1 K i 1 ) \left(\frac{H}{Ki}-\frac{L-1}{Ki}\right)^{N-1}\times\left(\frac{H}{Ki}-\frac{L-1}{Ki}-1\right) ,但是会多算一些,也就是最大公约数为 2 i , 3 i , 2i,3i,\cdots 的方案,所以最后再减去 f [ 2 i ] , f [ 3 i ] , f[2i],f[3i],\cdots 即可。

复杂度 O ( ( H L ) l o g ( H L ) ) O((H-L)log(H-L))

注意 :最后如果 K K L , H L,H 之间的话还要加上全部为 K K 的方案数,也就是1。

#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int M=1e5+10;
const ll Mod=1e9+7;
ll n,K,L,H,f[M],len,ls;
ll fpow(ll a,ll b){
	ll res=1;
	for(;b;b>>=1,a=(a*a)%Mod){
		if(b&1)res=(res*a)%Mod;
	}
	return res;
}
int main(){
	scanf("%lld%lld%lld%lld",&n,&K,&L,&H);
	if(L<=K&&K<=H)ls=1;
	ll l=(L-1)/K,r=H/K;
	len=r-l;
	for(int i=len;i>=1;i--){
		ll x=l/i,y=r/i;
		f[i]=fpow(y-x,n)-(y-x);
		if(f[i]<0)(f[i]%=Mod)+=Mod;
		for(ll j=i+i;j<=len;j+=i){
			f[i]=(f[i]-f[j])%Mod;
		}
		if(f[i]<0)f[i]+=Mod;
	}
	printf("%lld\n",f[1]+ls);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/VictoryCzt/article/details/85090284
今日推荐