[luogu P5218] 无聊的水题 II
\(\text{Problem}:\)无聊的水题 II
\(\text{Solution}:\)
即求有多少种方案使得选中的数的 \(\gcd\) 等于 \(1\)。
设 \(f(x)\) 表示选中的数的 \(\gcd\) 等于 \(x\) 的方案数,\(g(x)\) 表示选中的数的 \(\gcd\) 为 \(x\) 的倍数的方案数。有:
\[g(x)=\sum\limits_{x\mid d}f(d)\\
\]
而 \(g(x)\) 非常好求,即从 \(\lfloor\frac{n}{x}\rfloor\) 个数中选若干个(不为 \(0\)),易知为 \(2^{\lfloor\frac{n}{x}\rfloor}-1\)。
最后套上莫比乌斯反演,要求的为 \(f(1)\),有:
\[\begin{aligned}
f(x)&=\sum\limits_{x\mid d}\mu(\frac{d}{x})g(d)\\
f(1)&=\sum\limits_{i=1}^{n}\mu(i)g(i)\\
&=\sum\limits_{i=1}^{n}\mu(i)(2^{\lfloor\frac{n}{i}\rfloor}-1)
\end{aligned}
\]
整除分块求和即可。对于本题,需要利用杜教筛求 \(\mu\) 函数的前缀和。
\(\text{Code}:\)
#include <bits/stdc++.h>
#pragma GCC optimize(3)
#define int long long
#define ri register
#define mk make_pair
#define fi first
#define se second
#define pb push_back
#define eb emplace_back
#define is insert
#define es erase
#define vi vector<int>
#define vpi vector<pair<int,int>>
using namespace std; const int N=20000010, Mod=1e9+7;
inline int read()
{
int s=0, w=1; ri char ch=getchar();
while(ch<'0'||ch>'9') { if(ch=='-') w=-1; ch=getchar(); }
while(ch>='0'&&ch<='9') s=(s<<3)+(s<<1)+(ch^48), ch=getchar();
return s*w;
}
int n;
int pri[N/10],cnt,mu[N]; bool book[N];
inline int ksc(int x,int p) { int res=1; for(;p;p>>=1, x=x*x%Mod) if(p&1) res=res*x%Mod; return res; }
inline void Init()
{
mu[1]=1;
for(ri int i=2;i<N;i++)
{
if(!book[i]) pri[++cnt]=i, mu[i]=-1;
for(ri int j=1;j<=cnt&&i*pri[j]<N;j++)
{
book[i*pri[j]]=1;
if(i%pri[j]==0) break;
else mu[i*pri[j]]=-mu[i];
}
}
for(ri int i=1;i<N;i++) mu[i]+=mu[i-1];
}
map<int,int> Q;
int Smu(int x)
{
if(x<N) return mu[x];
if(Q.find(x)!=Q.end()) return Q[x];
int res=1;
for(ri int l=2,r;l<=x;l=r+1)
{
r=x/(x/l);
res-=Smu(x/l)*(r-l+1);
}
return Q[x]=res;
}
signed main()
{
Init(), n=read();
int ans=0;
for(ri int l=1,r;l<=n;l=r+1)
{
r=n/(n/l);
int w=ksc(2,(n/l)%(Mod-1))-1;
ans=(ans+w*(Smu(r)-Smu(l-1))%Mod)%Mod;
}
printf("%lld\n",(ans+Mod)%Mod);
return 0;
}
夜畔流离回,暗叹永无殿。
独隐万花翠,空寂亦难迁。
千秋孰能为,明灭常久见。
但得心未碎,踏遍九重天。