总感觉博客园的(Markdown)很。。(gouzhi),可以看这的。
(Description)
求$$sum_{i=1}^nsum_{j=1}^m[gcd(i,j)为质数]$$
(Solution)
[ egin{aligned}
Ans &=sum_{i=1}^nsum_{j=1}^m[(i,j)为质数]\
&=sum_{p}sum_{i=1}^nsum_{j=1}^m[(i,j)=p]\
&=sum_{p}sum_{i=1}^{lfloor{frac{n}{p}}
floor}sum_{j=1}^{lfloor{frac{m}{p}}
floor}[(i,j)=1]\
&=sum_{p}sum_{d=1}^{min(lfloor{frac{n}{p}}
floor,lfloor{frac{m}{p}}
floor)}mu(d)lfloorfrac{n}{pd}
floorlfloorfrac{m}{pd}
floor
end{aligned}
]
带着(pd)不舒服啊,令(t=pd),则
[ egin{aligned}
Ans &=sum_{p}sum_{d=1}^{min(lfloor{frac{n}{p}}
floor,lfloor{frac{m}{p}}
floor)}mu(d)lfloorfrac{n}{pd}
floorlfloorfrac{m}{pd}
floor\
&=sum_psum_{p|t}mu(frac{t}{p})lfloorfrac{n}{t}
floorlfloorfrac{m}{t}
floor\
&=sum_{t=1}^{min(n,m)}lfloorfrac{n}{t}
floorlfloorfrac{m}{t}
floorsum_{p|t}mu(frac{t}{p})
end{aligned}
]
前面那部分好求,后面那部分如果能用前缀和求的话就容易了。事实上也是可以的。
令(F(t)=sum_{p|t}mu(frac{t}{p})),那么$$Ans=sum_{t=1}^{min(n,m)}F(t)lfloorfrac{n}{t}
floorlfloorfrac{m}{t}
floor$$
对于每个(p)我们只需要暴力枚举约数(d)更新(F(pd))就可以了。
复杂度(转自ppt by (popoqqq)):由$$lim_{n
ightarrowinfty}sum_{i=1}^nfrac{1}{i}=ln n+r$$
易知,每个质数更新时是均摊(O(log n))的,而质数个数恰好为(O(frac{n}{log n})),所以暴力枚举+维护前缀和的时间复杂度为(O(n))。
计算复杂度自然就是(O(sqrt{n}))了。
另外(F(t)=sum_{p|t}mu(frac{t}{p}))是可以一起线性筛出来的。参考。
[ F(p*k)=
egin{cases}
mu(k), & pmid k\
mu(k)-F(k), & p
mid k
end{cases}
]
对于这个式子,(F(p*k)=sum_{p'|p*k}mu(frac{p*k}{p'}))
- (pmid k)时,有(p*k)的因子(p)的次数(geq 2)。
1.(p'=p)时,即(mu(k))。
2.(p' eq p)时,因为(p)的次数(geq 2),所以为(0)。
因此此时答案为(mu(k))。 - (p
mid k)时,有(p*k)的质因子(p)的次数为(1)。
1.(p'=p)时,也是(mu(k))。
2.(p' eq p)时,此时(p')与(p)互质,由(mu)的积性函数性质,可化为(sum_{p'|k}mu(frac{k}{p'})mu(p)),(mu(p)=-1),所以为(-sum_{p'|k}mu(frac{k}{p'})=-F(k))。
因此此时答案为(mu(k)-F(k))。
注意对于每个质数(p),(F(p)=1);(F(1)=0)。
线性筛(F(t)):
//131680kb 3380ms
#include <cstdio>
#include <cctype>
#include <algorithm>
#define gc() getchar()
typedef long long LL;
const int N=1e7+1;
int cnt,P[1000005],f[N+2],mu[N+2],sum[N+2];
bool Not_p[N+2];
void Make_Table()
{
mu[1]=1;/*f[1]=0;*/
for(int i=2; i<N; ++i)
{
if(!Not_p[i]) P[++cnt]=i,mu[i]=-1,f[i]=1;
for(int j=1; j<=cnt&&i*P[j]<N; ++j)
{
Not_p[i*P[j]]=1;
if(i%P[j]) mu[i*P[j]]=-mu[i], f[i*P[j]]=mu[i]-f[i];
else {mu[i*P[j]]=0, f[i*P[j]]=mu[i]; break;}
}
}
for(int i=1; i<N; ++i) sum[i]=sum[i-1]+f[i];
// for(int i=1; i<=cnt; ++i)
// for(int j=1; j*P[i]<N; ++j)
// sum[j*P[i]]+=mu[j];
// for(int i=2; i<N; ++i) sum[i]+=sum[i-1];
}
int main()
{
Make_Table();
int T,n,m; LL res;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m), res=0;
if(n>m) std::swap(n,m);
for(int nxt,i=1; i<=n; i=nxt+1)
{
nxt=std::min(n/(n/i),m/(m/i));
res+=1ll*(sum[nxt]-sum[i-1])*(n/i)*(m/i);
}
printf("%lld
",res);
}
return 0;
}
枚举约数:
//131680kb 4388ms
#include <cstdio>
#include <cctype>
#include <algorithm>
#define gc() getchar()
typedef long long LL;
const int N=1e7+1;
int cnt,P[1000005],mu[N+2];
LL sum[N+2];
bool Not_p[N+2];
void Make_Table()
{
mu[1]=1;
for(int i=2; i<N; ++i)
{
if(!Not_p[i]) P[++cnt]=i,mu[i]=-1;
for(int j=1; j<=cnt&&i*P[j]<N; ++j)
{
Not_p[i*P[j]]=1;
if(i%P[j]) mu[i*P[j]]=-mu[i];
else {mu[i*P[j]]=0; break;}
}
}
for(int i=1; i<=cnt; ++i)
for(int j=1; j*P[i]<N; ++j)
sum[j*P[i]]+=mu[j];
for(int i=2; i<N; ++i) sum[i]+=sum[i-1];
}
int main()
{
Make_Table();
int T,n,m; LL res;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m), res=0;
if(n>m) std::swap(n,m);
for(int nxt,i=1; i<=n; i=nxt+1)
{
nxt=std::min(n/(n/i),m/(m/i));
res+=(sum[nxt]-sum[i-1])*(n/i)*(m/i);
}
printf("%lld
",res);
}
return 0;
}