zoukankan      html  css  js  c++  java
  • bzoj 4176

    题意:求$sum_{i=1}^{n}sum_{j=1}^{n}d(ij)$

    首先推一发式子:

    $sum_{i=1}^{n}sum_{j=1}^{n}d(ij)$

    有一个结论:$d(nm)=sum_{i|n}sum_{j|m}[gcd(i,j)equiv 1]$

    然后代入,得:

    $sum_{i=1}^{n}sum_{j=1}^{n}sum_{p|i}sum_{q|j}[gcd(p,q)equiv 1]$

    然后优先枚举$p$,$q$,得到:

    $sum_{p=1}^{n}sum_{q=1}^{n}[gcd(p,q)equiv 1]sum_{p|i}sum_{q|j}1$

    那么也就是:

    $sum_{p=1}^{n}sum_{q=1}^{n}[gcd(p,q)equiv 1]frac{n}{p}frac{n}{q}$

    接下来就是常规步骤了

    $sum_{p=1}^{n}sum_{q=1}^{n}sum_{t|gcd(p,q)}mu(t)frac{n}{p}frac{n}{p}$

    也就是:

    $sum_{t=1}^{n}mu(t)sum_{p=1}^{frac{n}{t}}frac{n}{pt}sum_{q=1}^{frac{n}{t}}frac{n}{qt}$

     设$f(n)=sum_{i=1}^{n}frac{n}{i}$,那么后面就可以变成$sum_{t=1}^{n}mu(t)f(frac{n}{t})^{2}$

    求$f$可以数论分块,用杜教筛筛出$mu$的前缀和之后再套个数论分块即可

    代码:

    #include <cstdio>
    #include <cmath>
    #include <cstring>
    #include <cstdlib>
    #include <iostream>
    #include <algorithm>
    #include <queue>
    #include <stack>
    #include <map>
    #define ll long long
    using namespace std;
    const ll mode=1000000007;
    map <ll,ll> S;
    int mu[10000005];
    ll s[10000005];
    int pri[10000005];
    int cnt=0;
    bool used[10000005];
    void init()
    {
        mu[1]=s[1]=1;
        for(int i=2;i<=10000000;i++)
        {
            if(!used[i])pri[++cnt]=i,mu[i]=-1;
            for(int j=1;j<=cnt&&i*pri[j]<=10000000;j++)
            {
                used[i*pri[j]]=1;
                if(i%pri[j]==0){mu[i*pri[j]]=0;break;}
                mu[i*pri[j]]=-mu[i];
            }
            s[i]=(s[i-1]+mu[i]+mode)%mode;
        }
    }
    ll get_S(ll x)
    {
        if(x<=10000000)return s[x];
        else if(S.find(x)!=S.end())return S[x];
        ll ret=0;
        int las=0;
        for(int i=2;i<=x;i=las+1)
        {
            las=x/(x/i);
            ll temp=get_S(x/i);
            ret=(ret+temp*(las-i+1)+mode)%mode;
        }
        ret=(1+mode-ret)%mode;
        return S[x]=ret;
    }
    ll get_sum(ll x)
    {
        ll las=0,ret=0;
        for(int i=1;i<=x;i=las+1)
        {
            las=x/(x/i);
            ret+=(las-i+1)*(x/i)%mode;
            ret%=mode;
        }
        return ret*ret%mode;
    }
    ll solve(ll n)
    {
        ll las=0,ret=0;
        for(int i=1;i<=n;i=las+1)
        {
            las=n/(n/i);
            ret+=(get_S(las)-get_S(i-1)+mode)%mode*get_sum(n/i)%mode;
            ret%=mode;
        }
        return ret;
    }
    int main()
    {
        init();
        ll n;
        scanf("%lld",&n);
        printf("%lld
    ",solve(n));
        return 0;
    }
  • 相关阅读:
    codevs1004 四子连棋
    codevs1009 产生数
    NOIP2014 寻找道路
    Tyvj1139 向远方奔跑(APIO 2009 抢掠计划)
    随机算法
    线性基
    线性基入门
    线性基 + 并查集
    欧拉公式 (平面)
    卡特兰数 + 大数
  • 原文地址:https://www.cnblogs.com/zhangleo/p/11150275.html
Copyright © 2011-2022 走看看