题目链接

https://lydsy.com/JudgeOnline/problem.php?id=5332

题解

反演得到
d=1min(A,B)μ(d)e=1min(A,C)μ(e)f=1min(B,C)μ(f)F(lcm(d,e),A)F(lcm(d,f),B)F(lcm(e,f),C) \sum_{d=1}^{\min(A,B)}\mu(d)\sum_{e=1}^{\min(A,C)}\mu(e)\sum_{f=1}^{\min(B,C)}\mu(f)F(\mathrm{lcm}(d,e),A)F(\mathrm{lcm}(d,f),B)F(\mathrm{lcm}(e,f),C)
其中
F(a,b)=akbk F(a,b)=\sum_{a|k}\lfloor\frac{b}{k}\rfloor
可以对于每个b=A,B,Cb=A,B,CO(nlogn)O(n\log n)预处理出每个aa对应的FF值。

容易发现F(a,b)F(a,b)只有在aba\leq b时才有值,因此只要两个数x,yx,yμ(x)=0\mu(x)=0μ(y)=0\mu(y)=0lcm(x,y)>max(A,B,C)\mathrm{lcm}(x,y)>\max(A,B,C),那么在枚举过程中d,e,fd,e,f中任意两个=x=xyy,这次枚举就一定没有贡献了。

因此可以对于每个μ(x)\mu(x)μ(y)\mu(y)都不等于00并且lcm(x,y)max(A,B,C)\mathrm{lcm}(x,y)\leq \max(A,B,C)时,在x,yx,y间连一条权值为lcm(x,y)\mathrm{lcm}(x,y)边,那么对答案能产生贡献的就是这张图里面所有的三元环。

为了让建边不变成O(n2)O(n^2)的,考虑枚举边权,由于μ(x)\mu(x)μ(y)\mu(y)̸=0\not= 0,因此边权的μ\mu也不会=0=0,那么边权就一定可以拆成多个不同质因子之积。枚举这些质因子的子集作为xx,枚举xx的所有质因子的子集作为gcd(x,y)\gcd(x,y),容易得到yy,那么在xxyy间连一条边即可。

容(shi)易(ji)发(shang)现,这张图其实是稀疏的,边数不会很大。

因此O(mm)O(m\sqrt{m})的枚举三元环即可。

复杂度O(O(玄学))。(可能)需要一些卡常技巧。

代码

#include <cstdio>
#include <vector>
#include <algorithm>
 
int read()
{
  int x=0,f=1;
  char ch=getchar();
  while((ch<'0')||(ch>'9'))
    {
      if(ch=='-')
        {
          f=-f;
        }
      ch=getchar();
    }
  while((ch>='0')&&(ch<='9'))
    {
      x=x*10+ch-'0';
      ch=getchar();
    }
  return x*f;
}
 
const int maxn=100000;
const int maxm=1000000;
const int mod=1000000007;
 
int p[maxn+10],prime[maxn+10],cnt,mu[maxn+10];
std::vector<int> d[maxn+10];
 
int getprime()
{
  p[1]=mu[1]=1;
  for(int i=2; i<=maxn; ++i)
    {
      if(!p[i])
        {
          prime[++cnt]=i;
          mu[i]=-1;
        }
      for(int j=1; (j<=cnt)&&(i*prime[j]<=maxn); ++j)
        {
          int x=i*prime[j];
          p[x]=1;
          if(i%prime[j]==0)
            {
              mu[x]=0;
              break;
            }
          mu[x]=-mu[i];
        }
    }
  for(int i=1; i<=cnt; ++i)
    {
      for(int j=1; j<=maxn/prime[i]; ++j)
        {
          (mu[prime[i]*j])&&(d[prime[i]*j].push_back(prime[i]),0);
        }
    }
  return 0;
}
 
int getf(int *f,int b)
{
  for(int i=1; i<=b; ++i)
    {
      for(int j=i; j<=b; j+=i)
        {
          f[i]+=b/j;
          if(f[i]>=mod)
            {
              f[i]-=mod;
            }
        }
    }
  return 0;
}
 
struct edge
{
  int x,y,v;
 
  edge(int _x=0,int _y=0,int _v=0):x(_x),y(_y),v(_v){}
};
 
int T,A,B,C,fa[maxn+10],fb[maxn+10],fc[maxn+10],deg[maxn+10],cnte,tmp[maxn+10];
edge all[maxm+10];
std::vector<edge> e[maxn+10];
 
int main()
{
  getprime();
  T=read();
  while(T--)
    {
      A=read();
      B=read();
      C=read();
      (B<C)&&(std::swap(B,C),0);
      (A<B)&&(std::swap(A,B),0);
      (B<C)&&(std::swap(B,C),0);
      for(int i=1; i<=A; ++i)
        {
          int s=d[i].size(),full=(1<<s)-1;
          for(int j=0; j<full; ++j)
            {
              int x=1;
              for(int k=0; k<s; ++k)
                {
                  (j&(1<<k))&&(x*=d[i][k]);
                }
              int oth=i/x;
              for(int k=j; k>=0; k=(k-1)&j)
                {
                  int g=1;
                  for(int l=0; l<s; ++l)
                    {
                      (k&(1<<l))&&(g*=d[i][l]);
                    }
                  int y=g*oth;
                  (x<y)&&(all[++cnte]=edge(x,y,i),0);
                  if(k==0)
                    {
                      break;
                    }
                }
            }
        }
      for(int i=1; i<=cnte; ++i)
        {
          ++deg[all[i].x];
          ++deg[all[i].y];
        }
      for(int i=1; i<=cnte; ++i)
        {
          ((deg[all[i].x]>deg[all[i].y])
           ||((deg[all[i].x]==deg[all[i].y])&&(all[i].x<all[i].y)))
            ?(e[all[i].x].push_back(edge(all[i].x,all[i].y,all[i].v)))
            :(e[all[i].y].push_back(edge(all[i].y,all[i].x,all[i].v)));
        }
      getf(fa,A);
      getf(fb,B);
      getf(fc,C);
      int ans=0;
      for(int i=1; i<=A; ++i)
        {
          for(std::vector<edge>::iterator a=e[i].begin(); a!=e[i].end(); ++a)
            {
              tmp[a->y]=a->v;
            }
          for(std::vector<edge>::iterator a=e[i].begin(); a!=e[i].end(); ++a)
            {
              for(std::vector<edge>::iterator b=e[a->y].begin(); b!=e[a->y].end(); ++b)
                {
                  (tmp[b->y])&&
                    (((ans=(ans+mu[i]*mu[a->y]*mu[b->y]
                            *(1ll*fa[a->v]*fb[b->v]*fc[tmp[b->y]]
                              +1ll*fa[a->v]*fb[tmp[b->y]]*fc[b->v]
                              +1ll*fa[b->v]*fb[a->v]*fc[tmp[b->y]]
                              +1ll*fa[b->v]*fb[tmp[b->y]]*fc[a->v]
                              +1ll*fa[tmp[b->y]]*fb[a->v]*fc[b->v]
                              +1ll*fa[tmp[b->y]]*fb[b->v]*fc[a->v]))%mod)<0)&&(ans+=mod));
                }
            }
          for(std::vector<edge>::iterator a=e[i].begin(); a!=e[i].end(); ++a)
            {
              tmp[a->y]=0;
            }
        }
      for(int i=1; i<=A; ++i)
        {
          for(std::vector<edge>::iterator a=e[i].begin(); a!=e[i].end(); ++a)
            {
              ((ans=(ans+mu[i]*(1ll*fa[a->v]*fb[a->v]*fc[a->y]
                                +1ll*fa[a->v]*fb[a->y]*fc[a->v]
                                +1ll*fa[a->y]*fb[a->v]*fc[a->v])
                     +mu[a->y]*(1ll*fa[a->v]*fb[a->v]*fc[i]
                               +1ll*fa[a->v]*fb[i]*fc[a->v]
                               +1ll*fa[i]*fb[a->v]*fc[a->v]))%mod)<0)&&(ans+=mod);
            }
        }
      for(int i=1; i<=A; ++i)
        {
          ((ans=(ans+mu[i]*1ll*fa[i]*fb[i]*fc[i])%mod)<0)&&(ans+=mod);
        }
      printf("%d\n",ans);
      for(int i=1; i<=A; ++i)
        {
          fa[i]=0;
        }
      for(int i=1; i<=B; ++i)
        {
          fb[i]=0;
        }
      for(int i=1; i<=C; ++i)
        {
          fc[i]=0;
        }
      for(int i=1; i<=A; ++i)
        {
          deg[i]=0;
        }
      for(int i=1; i<=A; ++i)
        {
          e[i].clear();
        }
      cnte=0;
    }
  return 0;
}