题目链接:bzoj3309
题目大意:
对于正整数n,定义f(n)为n所含质因子的最大幂指数。给定正整数a,b,求
∑ai=1∑bj=1f(gcd(i,j))
。T<=10000,1<=a,b<=10^7
题解:
莫比乌斯反演+线性筛
sb的我一开始柿子都画错了
要求
ans=∑i=1a∑j=1bf(gcd(i,j))
即
∑i=1a∑j=1b∑d|i,d|j,gcd(i,j)=df(d)
(蒟蒻就是漏掉了 gcd(i,j)=d QWQ)
即
∑d=1min(a,b)∑i=1⌊ad⌋∑j=1⌊bd⌋f(d)[gcd(i,j)=1]
反演一下:
∑d=1min(a,b)f(d)∑i=1⌊ad⌋∑j=1⌊bd⌋∑t|i,t|jμ(t)
即
∑d=1min(a,b)f(d)∑t=1min(⌊ad⌋,⌊bd⌋)μ(t)×⌊adt⌋×⌊bdt⌋
修改求和指标,枚举T=dt
则式子变成
∑T=1min(a,b)⌊nT⌋×⌊mT⌋∑d|Tf(d)×μ(Td)
嗯..然后我就不会了。
一开始打错的时候以为只用预处理出 f(i) ,而现在要搞 ∑d|Tf(d)×μ(Td) 啊><。
接下来的看 这个吧。我觉得写得最详细了。嗯还是新出炉的。
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
#define N 10000100
bool ispri[N];LL f[N];int ct[N],g[N],pri[N/4],cnt;
int mymin(int x,int y){return (x<y)?x:y;}
void pre(int lim)
{
cnt=0;f[1]=0;ct[1]=0;
for (int i=2;i<=lim;i++)
{
if (!ispri[i]) {pri[++cnt]=i;f[i]=1;ct[i]=1;g[i]=i;}
for (int j=1;j<=cnt && i*pri[j]<=lim;j++)
{
int k=i*pri[j];
ispri[k]=true;
if (i%pri[j]==0)
{
ct[k]=ct[i]+1;
g[k]=g[i]*pri[j];
int tmp=i/g[i];
if (tmp==1) f[k]=1;
else f[k]=(ct[tmp]==ct[k])?-f[tmp]:0;
break;
}
ct[k]=1;g[k]=pri[j];
f[k]=(ct[i]==1)?-f[i]:0;
}
}
for (int i=2;i<=lim;i++) f[i]+=f[i-1];
}
int main()
{
//freopen("a.in","r",stdin);
//freopen("a.out","w",stdout);
int T,lim,n,m,i,r;LL ans;
scanf("%d",&T);
lim=10000000;pre(lim);
while (T--)
{
scanf("%d%d",&n,&m);
lim=mymin(n,m);ans=0;
for (i=1;i<=lim;i=r+1)
{
r=mymin(n/(n/i),m/(m/i));
ans+=(f[r]-f[i-1])*(LL)(n/i)*(LL)(m/i);
}
printf("%lld\n",ans);
}
return 0;
}