正题
bzoj没了,在darkbzoj交吧
题目链接:https://darkbzoj.tk/problem/3309
题目大意
定义f(x)f(x)f(x)表示xxx所有质因数中最大的指数幂。
求∑i=1n∑j=1mf(gcd(i,j))\sum_{i=1}^n\sum_{j=1}^mf(\ gcd(i,j)\ )i=1∑nj=1∑mf( gcd(i,j) )
解题思路
很显然要用莫反算,但是如果要算我们需要预处理∑d∣xf(d)μ(xd)\sum_{d|x}f(d)\mu(\frac{x}{d})∑d∣xf(d)μ(dx)的前缀和
考虑如何线性筛这个东西,我们先需要两个东西sizx,mulxsiz_x,mul_xsizx,mulx分别表示xxx的质因子个数,和所有质因子的一次幂乘积。然后这个东西很容易用线性筛处理出来,之后定义sumx=∑d∣xf(d)μ(xd)sum_x=\sum_{d|x}f(d)\mu(\frac{x}{d})sumx=∑d∣xf(d)μ(dx)。
那么当x=mulxx=mul_xx=mulx时,我们选择两次的质因子是没有意义的,因为这些数的μ\muμ为000。那么也就是一个大小为sizxsiz_xsizx的集合,每个子集SSS会产生(−1)∣S∣(-1)^{|S|}(−1)∣S∣的贡献,那么可以发现这些贡献的和就是(−1)sizx+1(-1)^{siz_x+1}(−1)sizx+1。
如果当一个y=x∗mulxy=x*mul_xy=x∗mulx时,也就是这些可以选择的数没有改变,所以同理sumy=sumxsum_y=sum_xsumy=sumx。
如果一个数不能被表达成以上形式时,它们的sumsumsum都为000。
然后线性筛加一个前缀和就好了,时间复杂度O(N+Tn+m)O(N+T\sqrt {n+m})O(N+Tn+m)
codecodecode
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const ll N=1e7+10;
ll T,n,m,cnt,pri[N],siz[N],mul[N],sum[N];
bool v[N];
void Prime(){for(ll i=2;i<N;i++){if(!v[i])pri[++cnt]=i,siz[i]=1,mul[i]=i;if(mul[i]==i)sum[i]=(siz[i]&1)?1:-1;if(sum[i]&&(ll)i*mul[i]<N)sum[i*mul[i]]=sum[i];for(ll j=1;j<=cnt&&i*pri[j]<N;j++){v[i*pri[j]]=1;if(i%pri[j]==0){siz[i*pri[j]]=siz[i];mul[i*pri[j]]=mul[i];break;}siz[i*pri[j]]=siz[i]+1;mul[i*pri[j]]=mul[i]*pri[j];}}for(ll i=1;i<N;i++)sum[i]+=sum[i-1];return;
}
int main()
{Prime();scanf("%lld",&T);while(T--){scanf("%lld%lld",&n,&m);if(n>m)swap(n,m);ll ans=0;for(ll l=1,r;l<=n;l=r+1){r=min(n/(n/l),m/(m/l));ans+=(n/l)*(m/l)*(sum[r]-sum[l-1]);}printf("%lld\n",ans);}
}