• 51nod 1237 最大公约数之和 V3


    求∑1<=i<=n1<=j<=ngcd(i,j) % P

    P = 10^9 + 7

    2 <= n <= 10^10

    这道题,明显就是杜教筛

    推一下公式:

    利用∑d|nphi(d) = n

    ans = ∑1<=i<=n1<=j<=nd|(i,j)phi(d)

          = ∑1<=d<=n1<=i<=n1<=j<=n[d|(i,j)]phi(d)

          = 1<=d<=nphi(d)1<=i<=n1<=j<=n[d|(i,j)]

          = 1<=d<=nphi(d)(n / d) * (n / d)

          = 1<=i<=nphi(i) * (n / i) * (n / i)

    这样我们就可以把i按照(n / i)分成sqrt(n)段,假如此时x = n / i,r = n / x

    则[i,r]这段的(n / i)都为x,则此时的贡献为x * x * i<=j<=rphi(j)

    这样的我们对于每一段,我们需要算[i,r]这一段的phi函数之和

    令g(n) = 1<=i<=nphi(i)

    则我们需要算的是g(r) - g(i - 1)

    那怎么算g(r)呢?因为这个时候r可能非常大

    我们知道:

    g(n) = n * (n + 1) / 2 - 2<=i<=ng(n / i)

    所以我们可以在O(n^(2/3))内等到g(n)

    本来我以为这样需要算sqrt(n)段,每一段最坏是O(n^(2/3)),所以时间复杂度是不行的,

    但是试写一下代码,交后,发现跑的很快,大概是有很多段的g都可以很快的求出来???

    我这里也不会算复杂度。。。

    代码:

                                                
      //File Name: nod1237.cpp
      //Created Time: 2017年01月04日 星期三 00时47分02秒
                                       
    #include <bits/stdc++.h>
    #define LL long long
    using namespace std;
    const int MAXN = (int)2e7 + 1;
    const int P = (int)1e9 + 7;
    bool check[MAXN];
    int prime[MAXN / 10];
    LL g[MAXN],inv_2;
    map<LL,LL> rem;
    void init(int n){
        int tot = 0;
        g[1] = 1;
        memset(check,false,sizeof(check));
        for(int i=2;i<=n;++i){
            if(!check[i]){
                prime[tot++] = i;
                g[i] = i - 1;
            }
            for(int j=0;j<tot;++j){
                if((LL)i * prime[j] > n) break;
                check[i * prime[j]] = true;
                if(i % prime[j] == 0){
                    g[i * prime[j]] = g[i] * prime[j] % P;
                    break;
                }
                else{
                    g[i * prime[j]] = g[i] * (prime[j] - 1) % P;
                }
            }
        }
        for(int i=1;i<=n;++i)
            g[i] = (g[i] + g[i - 1]) % P;
    }
    LL cal_g(LL n){
        if(n < MAXN) return g[n];
        if(rem.count(n)) return rem[n];
        LL res = (n % P) * ((n + 1) % P) % P * inv_2 % P;
        for(LL i=2,x,r;i<=n;){
            x = n / i;
            r = n / x;
            res = (res - (r - i + 1) % P * cal_g(x) % P + P) % P;
            i = r + 1;
        }
        rem[n] = res;
        return res;
    }
    LL solve(LL n){
        init(min(n,MAXN - 1LL));
        LL res = 0;
        for(LL i=1,x,r;i<=n;){
            x = n / i;
            r = n / x;
            res = (res + (x % P) * (x % P) % P * (cal_g(r) - cal_g(i - 1) + P) % P) % P;
            i = r + 1;
        }
        return res;
    }
    LL qp(LL x,LL y){
        LL res = 1;
        for(;y>0;y>>=1){
            if(y & 1) res = res * x % P;
            x = x * x % P;
        }
        return res;
    }
    int main(){
        inv_2 = qp(2,P - 2);
        LL n;
        scanf("%lld",&n);
        printf("%lld
    ",solve(n));
        return 0;
    }
  • 相关阅读:
    bzoj4810 [Ynoi2017]由乃的玉米田 bitset优化+暴力+莫队
    Ionic Js六:切换开关操作
    Ionic Js五:单选框操作
    Ionic Js四:复选框
    Ionic Js三:下拉刷新
    Ionic Js二:背景层
    Ionic Js一:上拉菜单(ActionSheet)
    Ionic入门十:icon(图标)
    Ionic入门九:颜色
    Ionic入门八:头部与底部
  • 原文地址:https://www.cnblogs.com/-maybe/p/6250737.html
Copyright © 2020-2023  润新知