[BZOJ3930][CQOI2015]选数
BZOJ
Luogu
原题因为\(H-L\le10^5\)的限制,其实可以不用杜教筛。不过去掉这个限制本题还是可做的。以下题解忽视这个条件并使用了杜教筛。
sol
首先\(L=\lfloor\frac {L-1}{K}\rfloor\),\(R=\lfloor\frac RK\rfloor\),转化为在这个区间里选出n个数使它们的\(\gcd\)等于1.这个显然可以反演得到
\[ans=\sum_{i=1}^{R}\mu(i)(\lfloor\frac Hi\rfloor-\lfloor\frac Li\rfloor)^n
\]
后面一坨分块,然后需要快速求出\(\mu(i)\)的前缀和。
杜教筛即可。
code
#include<cstdio>
#include<algorithm>
#include<map>
using namespace std;
const int mod = 1000000007;
const int N = 5000000;
int gi()
{
int x=0,w=1;char ch=getchar();
while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
if (ch=='-') w=0,ch=getchar();
while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return w?x:-x;
}
int fastpow(int a,int b)
{
int res=1;
while (b) {if (b&1) res=1ll*res*a%mod;a=1ll*a*a%mod;b>>=1;}
return res;
}
int n,k,L,R,maxN,pri[N+5],tot,zhi[N+5],mu[N+5];
map<int,int>M;
void Mobius()
{
zhi[1]=mu[1]=1;
for (int i=2;i<=N;i++)
{
if (!zhi[i]) pri[++tot]=i,mu[i]=-1;
for (int j=1;j<=tot&&i*pri[j]<=N;j++)
{
zhi[i*pri[j]]=1;
if (i%pri[j]) mu[i*pri[j]]=-mu[i];
else break;
}
}
for (int i=1;i<=N;i++) mu[i]+=mu[i-1];
}
int Mu(int x)
{
if (x<=maxN) return mu[x];
if (M[x]) return M[x];
int i=2,j,res=0;
while (i<=x)
{
j=x/(x/i);
res=(res+1ll*(j-i+1)*Mu(x/i)%mod)%mod;
i=j+1;
}
return M[x]=(1-res+mod)%mod;
}
int main()
{
n=gi();k=gi();L=(gi()-1)/k;R=gi()/k;
maxN=min(N,R);
Mobius();
int i=1,j,ans=0;
while (i<=R)
{
j=R/(R/i);if (L/i) j=min(j,L/(L/i));
ans=(ans+1ll*(Mu(j)-Mu(i-1)+mod)%mod*fastpow(R/i-L/i,n)%mod)%mod;
i=j+1;
}
printf("%d\n",ans);
return 0;
}