• YY的GCD


    传送门

    题目描述很清楚,还是先老套路枚举gcd,不过这次你枚举的只能是质数。

    [sum_{i=1}^nsum_{j=1}^msum_{d=1,d is prime}^n[gcd(i,j)=d] ]

    这个式子我们很熟悉。直接d除进去然后套莫比乌斯函数的性质:

    [sum_{d=1,d is prime}^n sum_{p=1}^{frac{n}{d}}mu(p)leftlfloorfrac{n}{dp} ight floorleftlfloorfrac{m}{dp} ight floor ]

    这个式子的形式好像非常熟悉……?后面那一大串在d固定的时候,是可以整除分块(O(sqrt{n}))计算的。然后前面的那一层循环枚举质数,其实只是对你里面莫比乌斯函数的值有影响,这个也可以用前缀和维护的。

    然后在前面随便枚举的时候,我们是使用过类似埃氏筛法的方法统计的。这次也一样,直接用所有筛出来的素数更新其倍数的莫比乌斯函数前缀和即可,之后对于每组询问整除分块做。

    这题不知道为啥……我和别人都是一个算法但是跑的死慢……不开O2过不去……

    // luogu-judger-enable-o2
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<iostream>
    #include<cmath>
    #include<set>
    #include<vector>
    #include<map>
    #include<queue>
    #define rep(i,a,n) for(int i = a;i <= n;i++)
    #define per(i,n,a) for(int i = n;i >= a;i--)
    #define enter putchar('
    ')
    #define fr friend inline
    #define y1 poj
    #define mp make_pair
    #define pr pair<int,int>
    #define fi first
    #define sc second
    #define pb push_back
    #define I puts("bug")
    
    using namespace std;
    typedef long long ll;
    const int M = 10000005;
    const int INF = 1000000009;
    const double eps = 1e-7;
    const double pi = acos(-1);
    const ll mod = 1e9+7;
    
    ll read()
    {
        ll ans = 0,op = 1;char ch = getchar();
        while(ch < '0' || ch > '9') {if(ch == '-') op = -1;ch = getchar();}
        while(ch >= '0' && ch <= '9') ans = ans * 10 + ch - '0',ch = getchar();
        return ans * op;
    }
    
    ll T,n,m,p[M],tot,mu[M],sum[M],g[M];
    bool np[M];
    
    void euler()
    {
       np[1] = 1,mu[1] = 1;
       rep(i,2,M-2)
       {
          if(!np[i]) p[++tot] = i,mu[i] = -1;
          for(int j = 1;i * p[j] <= M-2;j++)
          {
         np[i * p[j]] = 1;
         if(!(i % p[j])) break;
         mu[i * p[j]] = -mu[i]; 
          }
       }
       rep(j,1,tot)
          for(int i = 1;i * p[j] <= M-2;i++) g[i * p[j]] += mu[i];
       rep(i,1,M-2) sum[i] = sum[i-1] + g[i];
    }
    
    int main()
    {
       euler();
       T = read();
       while(T--)
       {
          n = read(),m = read();
          ll k = min(n,m),ans = 0;
          for(int i = 1,j;i <= k;i = j+1)
          {
         j = min(n / (n / i),m / (m / i));
         ans += (ll)(n / i) * (m / i) * (ll)(sum[j] - sum[i-1]);
          }
          printf("%lld
    ",ans);
       }
       return 0;
    }
    
    
  • 相关阅读:
    C# Dev PropertyGrid
    C# PropertyGrid控件应用心得
    FileWriter不覆盖
    FileWriter
    java试题
    Java线程池
    java自带线程池和队列详细讲解
    HashMap练习题
    Map集合
    java指定
  • 原文地址:https://www.cnblogs.com/captain1/p/10122376.html
Copyright © 2020-2023  润新知