zoukankan      html  css  js  c++  java
  • LOJ 6229 LCM / GCD (杜教筛+Moebius)

    链接:

    https://loj.ac/problem/6229

    题意:

    $$F(n)=sum_{i=1}^nsum_{j=1}^ifrac{mathrm{lcm}(i,j)}{mathrm{gcd}(i,j)}$$

    让你求 (F(n) mod1000000007)

    题解:

    (egin{align} f(n)=sum_{i=1}^nfrac{lcm(i,n)}{gcd(i,n)}&=sum_{i=1}^nfrac{n*i}{(i,n)^2}\ &=sum_{i=1}^nsum_{d|n}[(i,n)=d]frac{n*i}{d^2}\ &=sum_{d|n}sum_{i=1}^{[frac nd]}[(i,frac nd)=1]frac{n*i}d\ &=sum_{d|n}dsum_{i=1}^d[(i,d)=1]*i\ &=frac 12(1+sum_{d|n}d^2varphi(d)) end{align})

    即求 (sum_{i=1}^nsum_{d|i}d^2varphi(d)=sum_{i=1}^nsum_{d=1}^{[frac ni]}d^2varphi(d))

    (phi'(n)=sum_{i=1}^ni^2varphi(i))

    因为 (sum_{d|n}d^2varphi(d)*(frac nd)^2=n^2sum_{d|n}varphi(d)=n^3)

    所以,

    (egin{align} sum_{i=1}^ni^3=[frac{n(n+1)}{2}]^2&=sum_{i=1}^nsum_{d|i}d^2varphi(d)*(frac id)^2\ &=sum_{i=1}^ni^2sum_{d=1}^{[ frac ni]}d^2varphi(d)\ &=sum_{i=1}^ni^2phi'([frac ni]) end{align})

    所以得到:(phi'(n)=[frac{n(n+1)}{2}]^2-sum_{i=2}^ni^2phi'([frac ni]))

    可以杜教筛先预处理前 (n^{2/3}),原问题可以在复杂度(O(n^{2/3}log(n)))内解决。

    整合一下,就是:

    推公式可以得到( 结合公式4 ):(ans=sum_{d=1}^nsum_{i=1}^{lfloor{nover d} floor}sum_{j=1}^i ij[gcd(i,j)=1])

    因为存在恒等式:(sum_{i=1}^ni[gcd(i,n)=1]={[n=1]+nvarphi(n)over 2})

    所以有:(ans={nover 2}+{1over 2}sum_{d=1}^nsum_{i=1}^{lfloor{nover d} floor}i^2varphi(i))

    考虑 (sum_{i=1}^{n}i^2varphi(i))出现的次数,可以得到: (ans={nover 2}+{1over 2}sum_{i=1}^ni^2varphi(i)lfloor{nover i} floor)

    其中,(sum_{i=1}^ni^2 = frac{ncdot(n+1)cdot(2n+1)}{6})(varphi(i))为欧拉函数。

    代码:

    #include <bits/stdc++.h>
    
    using namespace std;
    typedef long long ll;
    const int maxn = 1e6+100;
    const int mod = 1e9+7;
    int n;
    int p[maxn],phi[maxn],pre[maxn];
    
    int inv2,inv6;
    ll qpower(ll a,ll b,ll mod)
    {
      ll res = 1;
      while(b>0) {
        if(b&1) res = res * a % mod;
        b >>= 1;
        a = a * a % mod;
      }
      return res;
    }
    void init(int n)
    {
      phi[1]=1;
      for(int i=2;i<=n;i++)
      {
        if(p[i]==0) p[++*p]=i,phi[i]=i-1;
        for(int j=1;j<=*p && 1LL*p[j]*i<=n;j++)
        {
          p[p[j]*i]=1;
          if(i%p[j]) phi[i*p[j]]=phi[i]*phi[p[j]];
          else
          {
            phi[i*p[j]]=phi[i]*p[j];
            break;
          }
        }
      }
      for(int i=1;i<=n;i++) {
        pre[i]=(pre[i-1]+1LL*phi[i]*i%mod*i)%mod;
      }
    }
    map<ll,int> mp;
    int calcinv2(ll l,ll r)
    {
      l %= mod;
      r %= mod;
      return (r - l + 1) * (l + r) % mod * inv2 % mod;
    }
    int calcinv6(ll n)
    {
      n %= mod;
      return n * (n + 1) % mod * (2 * n + 1) % mod * inv6 % mod;
    }
    int calc2(ll l,ll r)
    {
     return (calcinv6(r) - calcinv6(l-1) ) % mod;
    }
    int calc3(ll n)
    {
      return 1LL * calcinv2(1 , n) * calcinv2(1 , n) % mod;
    }
    int S(ll n)
    {
      if(n <= 1e6) return pre[n];
      if(mp.count(n)) return mp[n];
      int res = calc3(n);
      for(ll i = 2, j; i <= n ;i = j + 1) {
        j = n / (n / i);
        res = (res - 1LL * calc2(i,j) * S(n / i)) % mod;
      }
      return mp[n] = res;
    }
    int main(int argc, char const *argv[]) {
    
      ll n;
      std::cin >> n;
      init(1000000);// 2/3
      inv2 = qpower(2,mod-2,mod);
      inv6 = qpower(6,mod-2,mod);
      int ans = 0;
      int last = 0;
      for(ll i = 1, j; i <= n; i = j + 1) {
        j = n /( n / i );
        int cur = S(j);
        ans = (ans + 1LL * (cur - last) * ( n / i)) % mod;
        last  = cur;
      }
      ans = (ans + n) % mod * inv2 % mod;
      std::cout << (ans + mod) % mod << '
    ';
      cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.
    ";
      return 0;
    }
    
    
  • 相关阅读:
    mongodb 3.4复制搭建
    mongodb 用户管理
    mongodb 3.4 TAR包启动多个实例
    mongodb 3.4 YUM安装
    mongodb数据库备份恢复-windows系统
    mongodb数据库索引管理
    mongodb数据库集合操作
    Unity3d 实现鼠标左键点击地形使角色移动到指定地点[脚本]
    Unity3D性能优化之Draw Call Batching
    Unity3D占用内存太大怎么解决呢?
  • 原文地址:https://www.cnblogs.com/LzyRapx/p/8459266.html
Copyright © 2011-2022 走看看