2 条题解

  • 0
    @ 2025-12-24 19:46:37
    • 0
      @ 2025-12-18 15:10:54

      G37 狄利克雷卷积

      G38 和式的变换

      G39 莫比乌斯反演

      问题

      给出 n,m,kn,m,k1n,m,k1051 \leq n,m,k \leq 10^5),求$\sum\limits_{i=1}^n\sum\limits_{j=1}^m \lbrack \gcd(i,j)=k \rbrack$

      即:满足 1in1 \leq i \leq n1jm1 \leq j \leq m,且 gcd(i,j)=k\gcd(i,j)=k 的二元组 (i,j)(i,j) 的数量。

      题解

      $\sum\limits_{i=1}^n\sum\limits_{j=1}^m\lbrack\gcd(i,j)=k\rbrack$
      $\sum\limits_{i=1}^{\frac{n}{k}}\sum\limits_{j=1}^{\frac{m}{k}}\lbrack\gcd(i,j)=1\rbrack$ 下来 nkmk\frac{n}{k},\frac{m}{k} 替换为 n,mn,m
      $=\sum\limits_{i=1}^n\sum\limits_{j=1}^m\sum\limits_{d |\gcd(i,j)}\mu(d)$ 注:[gcd(i,j)=1]\lbrack\gcd(i,j)=1\rbrack 变成 dgcd(i,j)μ(d)\sum\limits_{d|\gcd(i,j)}\mu(d) 是 黄金变换操作。
      $\sum\limits_{i=1}^n\sum\limits_{j=1}^m\sum\limits_{d=1}^n \lbrack d|i \rbrack \lbrack d|j \rbrack \mu(d)$ 注:dgcd(i,j)μ(d)\sum\limits_{d|\gcd(i,j)}\mu(d) 变为 $\sum\limits_{d=1}^n \lbrack d|i \rbrack \lbrack d|j \rbrack \mu(d)$ 是银变换操作。
      $=\sum\limits_{d=1}^n \mu(d)\sum\limits_{i=1}^n\lbrack d|i \rbrack \sum\limits_{j=1}^m\lbrack d|j \rbrack$ 注:调换for循环的顺序
      $=\sum\limits_{d=1}^n\mu(d) \lfloor \frac{n}{d} \rfloor \lfloor \frac{m}{d}\rfloor$ 注: $\sum\limits_{i=1}^n\lbrack d|i \rbrack 变为 \lfloor \frac{n}{d} \rfloor$ 铜变换操作。

      到此,在 d=1n\sum\limits_{d=1}^nμ(d)\mu(d) 可以前缀和, $\lfloor \frac{n}{d} \rfloor \lfloor \frac{m}{d}\rfloor$ 可以分块加速即可,从而避免了 dd 逐个枚举 1n1 \dots n

      具体代码如下:

      #include<bits/stdc++.h>
      #define LL long long
      using namespace std;
      const int N=5e4;
      int pr, p[N+10];LL mu[N+10]; bool v[N+10];
      void init()
      {
      	memset(v,0,sizeof(v));
      	pr=0;mu[0]=0;mu[1]=1;
          for(int i=2;i<=N;i++)
      	{
              if(!v[i]) p[++pr]=i, mu[i]=-1; 
              for(int j=1;j<=pr&&p[j]*i<=N;j++)
      		{
                  v[i*p[j]]=true;
                  if(i%p[j]==0){mu[i*p[j]]=0;break;}
                  mu[i*p[j]]=-mu[i];
              }
          }
          for(int i=1;i<=N;i++) mu[i]+=mu[i-1];
      }
      LL calc(int n, int m)
      {
          if(n>m)swap(n,m);
      	LL ans=0;
          for(int l=1,r;l<=n;l=r+1)
      	{
              r=min(n/(n/l), m/(m/l));
              ans+=(mu[r]-mu[l-1])*(n/l)*(m/l);
          }
          return ans;
      }
      int main()
      {
      	init();
      	int T,n,m,k;scanf("%d",&T);
      	while(T--)
      	{
              scanf("%d%d%d",&n,&m,&k);
      		n/=k;m/=k; 
              printf("%lld\n",calc(n,m));
      	}
          return 0;
      }
      
      • @ 2025-12-24 12:36:14

        第一步把n,m替换为n/k,m/k是指把i,j统一出k吗?

    • 1

    信息

    ID
    2754
    时间
    30000ms
    内存
    64MiB
    难度
    6
    标签
    递交数
    83
    已通过
    28
    上传者