zoukankan      html  css  js  c++  java
  • 51NOD 1237 最大公约数之和 V3(杜教筛)

    题意

    求 $sum_{i=1}^n sum_{j=1}^n gcd(i,j)$.

    分析

    $$egin{aligned}
    sum_{i=1}^n sum_{j=1}^n gcd(i,j)  &= sum_{i=1}^n sum_{j=1}^n d[gcd(i, j)=d] \
    &= sum_{d=1}^n d sum_{i=1}^n sum_{j=1}^n[gcd(i,j=d)] \
    &= sum_{d=1}^n d sum_{i=1}^{left lfloor frac{n}{d} ight floor}mu (i) left lfloor frac{n}{id} ight floorleft lfloor frac{n}{id} ight floor \
    &= sum_{T=1}^n ({frac{n}{T}})^2 sum_{d|T}dmu (frac{T}{d}) \
    &= sum_{T=1}^n ({frac{n}{T}})^2 varphi (T)
    end{aligned}$$

    使用了几个套路,

    一是 $gcd(i,j)=d$ 的经典求和式子;

    二是出现 $sum_{d=1}^n d sum_{i=1}^{left lfloor frac{n}{d} ight floor}$,枚举 $T=id$;

    三是使用结论 $mu * ID = varphi$.

    求欧拉函数的前缀和可以使用杜教筛。

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn = 2000010;
    typedef long long ll;
    const ll mod = 1000000007;
    const ll inv2 = (mod+1)>>1;
    ll T, n, pri[maxn], tot, phi[maxn], sum_phi[maxn];
    bool vis[maxn];
    unordered_map<ll, ll> mp_phi;  //可换成unordered_map
    ll S_phi(ll x) {
      if (x < maxn) return sum_phi[x];
      if (mp_phi[x]) return mp_phi[x];
      ll ret = (x%mod) * ((x+1)%mod) % mod * inv2 % mod;
      for (ll i = 2, j; i <= x; i = j + 1) {
        j = x / (x / i);
        ret =(ret - S_phi(x / i) * (j - i + 1) % mod + mod) % mod;
      }
      return mp_phi[x] = ret;
    }
    void initPhi()
    {
      phi[1] = 1;
      for (int i = 2; i < maxn; i++) {
        if (!vis[i]) pri[++tot] = i, phi[i] = i-1;
        for (int j = 1; j <= tot && i * pri[j] < maxn; j++) {
          vis[i * pri[j]] = true;
          if (i % pri[j] == 0)
          {
              phi[i * pri[j]] = phi[i] * pri[j] % mod;
              break;
          }
          else
          {
              phi[i * pri[j]] = phi[i] * phi[pri[j]] % mod;
          }
        }
      }
      for (int i = 1; i < maxn; i++) sum_phi[i] = (sum_phi[i - 1] + phi[i]) % mod;
    }
    
    void solve()
    {
        ll res = 0;
        for(ll i = 1, j;i <= n;i = j+1)
        {
            j = n / (n / i);
            ll tmp = (n/i) % mod;
            res = (res + tmp * tmp % mod * (S_phi(j)-S_phi(i-1) + mod) % mod) % mod;
        }
        printf("%lld
    ", res);
    }
    
    int main() {
      initPhi();
      scanf("%lld", &n);
      solve();
      return 0;
    }

    参考链接:

    1. http://www.ishenping.com/ArtInfo/1581096.html

    2. https://oi-wiki.org/math/du/

  • 相关阅读:
    507.Perfect Number
    441.Arranging Coins
    344.Reverse String
    160.Intersection of Two Linked Lists
    HDU-2521 反素数
    HDU-2710 Max Factor
    HDU-2552 三足鼎立
    HDU-2549 壮志难酬
    HDU-2548 两军交锋
    HDU-2550 百步穿杨
  • 原文地址:https://www.cnblogs.com/lfri/p/11701280.html
Copyright © 2011-2022 走看看