bzoj3930 & 洛谷P3172 [CQOI2015]選數 狄利克雷卷積+杜教篩+快速冪

題目鏈接:
bzoj3930
洛谷P3172

前置技能:
快速冪(霧)
杜教篩
狄利克雷卷積(莫比烏斯反演)

首先把答案表示出來:
這裏先把LLRR都除以kk,然後gcd=kgcd=k就轉化成gcd=1gcd=1
ans=Σx1=LRΣx2=LR...Σxn=LR[gcd(x1,x2,...,xn)=1]ans=\Large\Sigma\large_{x_1=L}^R\Large\Sigma\large_{x_2=L}^R...\Large\Sigma\large_{x_n=L}^R[gcd(x_1,x_2,...,x_n)=1]
μI=ε\mu*I=ε珂得
ans=Σx1=LRΣx2=LR...Σxn=LRΣdgcd(x1,x2,...,xn)μ(d)ans=\Large\Sigma\large_{x_1=L}^R\Large\Sigma\large_{x_2=L}^R...\Large\Sigma\large_{x_n=L}^R\Large\Sigma\large_{d|gcd(x_1,x_2,...,x_n)}\mu(d)
=Σx1=LRΣx2=LR...Σxn=LRΣdx1,dx2,...,dxnμ(d)=\Large\Sigma\large_{x_1=L}^R\Large\Sigma\large_{x_2=L}^R...\Large\Sigma\large_{x_n=L}^R\Large\Sigma\large_{d|x_1,d|x_2,...,d|x_n}\mu(d)
調換枚舉順序,先枚舉dd,得到
ans=Σd=1Rμ(d)Σdx1Σdx2...Σdxn1ans=\Large\Sigma\large_{d=1}^R\mu(d)\Large\Sigma\large_{d|x_1}\Large\Sigma\large_{d|x_2}...\Large\Sigma\large_{d|x_n}1
=Σd=1Rμ(d)(RdL1d)n=\Large\Sigma\large_{d=1}^R\mu(d)(\lfloor\frac{R}{d}\rfloor-\lfloor\frac{L-1}{d}\rfloor)^n

然後整除分塊,求一下μ\mu的前綴和(杜教篩),然後再來個快速冪即可qwq。

代碼

#include<stdio.h>
#include<cstring>
#include<algorithm>
#include<map>
#define re register int
#define rl register ll
#define mod 1000000007
using namespace std;
typedef long long ll;
int read() {
	re x=0,f=1;
	char ch=getchar();
	while(ch<'0' || ch>'9') {
		if(ch=='-')    f=-1;
		ch=getchar();
	}
	while(ch>='0' && ch<='9') {
		x=10*x+ch-'0';
		ch=getchar();
	}
	return x*f;
}
inline ll fpow(ll b,ll p,ll k) {
	ll ans=1;
	while(p) {
		if(p&1)	ans=ans*b%k;
		b=b*b%k;
		p>>=1;
	}
	return ans;
}
const int Size=2000005;
int tot,mu[Size],sum[Size],prime[Size];
bool vis[Size];
void getp(int maxn) {
	mu[1]=1;
	for(re i=2; i<=maxn; i++) {
		if(!vis[i]) {
			prime[++tot]=i;
			mu[i]=-1;
		}
		for(re j=1; j<=tot; j++) {
			int now=i*prime[j];
			vis[now]=true;
			if(now>maxn || i%prime[j]==0) {
				break;
			}
			mu[now]=-mu[i];
		}
	}
	for(re i=1; i<=maxn; i++) {
		sum[i]=sum[i-1]+mu[i];
	}
}
ll n,k,l,r;
//ll val[Size];
map<int,ll> val;
ll Sum(int x) {
	if(x<=1000000)	return sum[x];
	int t=r/x,lst;
	if(val[x])	return val[x];
	ll ans=0;
	for(re i=2; i<=x; i=lst+1) {
		lst=x/(x/i);
		ans=(ans+(ll)(lst-i+1)*Sum(x/i))%mod;
	}
//	vis[t]=true;
	return val[x]=(1ll-ans+mod)%mod;
}
int main() {
//	freopen("WA.txt","w",stdout);
	getp(1000000);
	memset(vis,0,sizeof(vis));
	n=read();
	k=read();
	l=(read()-1)/k;
	r=read()/k;
	int lst,cnt=0;
	ll ans=0;
	for(re i=1; i<=r; i=lst+1) {
		int tmpl=l/i,tmpr=r/i;
		//注意特判l/i=0的情況,小心RE
		if(!tmpl) {
			lst=r/tmpr;
		} else {
			lst=min(l/tmpl,r/tmpr);
		}
		ans=((ans+fpow(tmpr-tmpl,n,mod)*(Sum(lst)-Sum(i-1)+mod)%mod)+mod)%mod;
//		printf("%lld\n",ans);
	}
	printf("%lld",ans);
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章