题解 P2257 【YY的GCD】
在这里提供一个新思路
想必大家都做过这个题吧
有一种做法是利用
从而可以
那么这个题让我们求
怎么办??
如果有个函数(设为
没有还不能自己造嘛?
应该可以通过莫比乌斯反演找到另外一个数论函数求得我们的这个(其实是我不会)
有一种方法可以通过一些加加减减来获得这个函数,就是我先让
其核心就是再让
这样的话不就有
(除了f(n)的初值以外其他前面的函数值的和都被抵消掉了)
然后附上实现第二步的代码(赋初值的代码就省略掉了)
for (int i=1;i<=MAX;++i)
for (int j=i<<1;j<=MAX;j+=i)
f[j]-=f[i];
这两层for循环第二维是一个调和级数,总复杂度约为
这种方法也是比较常用的吧,有些题目里面也需要自己用这个方法构造函数,而且它的常数也比直接用莫比乌斯反演还小(我们学校的同学竟然出了卡莫比乌斯反演的数据,让我们只能用这种方法求)
那么这个题就愉快地结束了,除了复杂度是
最后感谢DT_Kang神犇的指导,以及附上AC代码
#include<cstdio>
#define N 10230040
#define U 10000000
#define ll long long
int min(int a,int b) {return a<b?a:b;}
long long f[N];int prime[N/10],cnt;bool ip[N];//其实10000000内只有660000个质数
int read(){//丑陋的快读
int n=0;char a;bool z=false;
while(a=getchar())
{
if (a>'9'||a<'0')
if (z) break;
else continue;
if (!z) z=true;
n=(n<<1)+(n<<3)+(a^48);
}
return n;
}
int main()
{
int n,T,m,up,R;ll ans=0;
for (int i=2;i<=U;++i)
{
if (!ip[i])
{
prime[++cnt]=i;
f[i]=1;
}
for (int j=1;j<=cnt&&i*prime[j]<=U;++j)
{
ip[i*prime[j]]=true;
if (i%prime[j]==0) break;
}
}
for (int i=2;i<=U;++i)
for (int j=i<<1;j<=U;j+=i)
f[j]-=f[i];
for (int i=2;i<=U;++i) f[i]+=f[i-1];
T=read();
while(T--)
{
ans=0;
n=read();m=read();up=min(n,m);
for (int i=1;i<=up;i=R+1)
{
R=min(n/(n/i),m/(m/i));
ans+=1ll*(f[R]-f[i-1])*(n/i)*(m/i);
}
printf("%lld\n",ans);
}
return 0;
}