• BZOJ 4804: 欧拉心算 欧拉函数


    4804: 欧拉心算

    >原题链接<

    Description

     给出一个数字N

    Input

    第一行为一个正整数T,表示数据组数。
    接下来T行为询问,每行包含一个正整数N。
    T<=5000,N<=10^7

    Output

    按读入顺序输出答案。

    Sample Input

    1
    10

    Sample Output

    136

    思路:

    考虑化简原式,设gcd(i,j) = p
    则原式可化为
    $sumlimits_{p=1}^{n} sumlimits_{i=1}^{n} sumlimits_{j=1}^{n} varphi(p)[gcd(i,j)=p]$
    由于$varphi(p)$和i、j均无关,故我们可以把$varphi(p)$提到前面化为
    $sumlimits_{p=1}^{n} varphi(p)sumlimits_{i=1}^{n} sumlimits_{j=1}^{n}[gcd(i,j)=p]$
    考虑把$[gcd(i,j)=p]$ 中的p除到前面,则原式可化为
    $sumlimits_{p=1}^{n} varphi(p)sumlimits_{i=1}^{lfloor n/p floor} sumlimits_{j=1}^{lfloor n/p floor}[gcd(i,j)=1]$
    这时我们设一个函数f(n) 表示 $sumlimits_{i=1}^{n}sumlimits_{j=1}^{n}[gcd(i,j)=1]$
    则原式可视为 $sumlimits_{p=1}^{n} varphi(p)*f(lfloor n/p floor)$
    考虑化简函数f(n) 。我们发现这个函数和欧拉函数相当相像。首先我们只考虑$ige j$的情况;
      即为
    $sumlimits_{i=1}^{n} sumlimits_{j=1}^{i}[gcd(i,j)=1] => sumlimits_{i=1}^{n}varphi(i)$
      同理,我们发现只考虑$ile j$的情况,
    也为$sumlimits_{j=1}^{n}varphi(j)$
    两种情况同时考虑,发现有一种$i=j$的情况重复,故$f(n)$最终可化简为$2 imessumlimits_{i=1}^{n}varphi(i) -1$
    综上所述,我们可以发现$ans = sumlimits_{p=1}^{n} varphi(p) imes ( (2 imessumlimits_{i=1}^{n}varphi(i)) -1)$
    现在我们有了一个$O(2 imes n)$的方法求解$ans$ 但是数据组数为$T = 5000$ .
    我们需要更加优化的方法才能解决问题,
    刚刚的2 * n中有一个n是预处理出$varphi()$以及其前缀和。
    是不和T相乘的,故我们考虑把每个答案$O(sqrt n)$处理
    发现在处理$s[lfloor n/p floor]$中,$lfloor n/p floor$在每一段的值都是相同的,共有约$sqrt n$段,
    而根据乘法结合律,我们可以先把$varphi()$加到一起,
    再来乘这个相等的s。s是在预处理中做好的,
    故总的时间复杂度为$O(2 imes n + T imes sqrt n)$
    下面附上代码
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    const int N = 10000001;
    int phi[N+10], pr[N+10], tot;
    bool np[N+10];
    long long s[N+10];
    void getphi() {
        int i, j;
        phi[1] = 1;
        for(i=2;i<=N;i++) {
            if(!np[i]) {
                pr[++tot] = i;
                phi[i] = i-1;
            }
            for(j=1;j<=tot&&i*pr[j]<=N;j++) {
                np[i*pr[j]]=1;
                if(i%pr[j] == 0) {
                    phi[i*pr[j]]=phi[i]*pr[j];
                    break;
                }
                else
                    phi[i*pr[j]]=phi[i]*(pr[j] - 1);
            }
        }
        for(i=1;i<=N;i++) {
            s[i]=s[i-1]+phi[i];
        }
    }
    int main() {
        int t;
        scanf("%d",&t);
        getphi();
        while(t--) {
            int n;
            long long ans=0;
            scanf("%d",&n);
            int lst =0;
            for(int p=1;p<=n;p=lst+1) {
                lst = n/(n/p);
                ans+=(s[lst]-s[p-1])*(s[n/p]*2-1);
            }
            printf("%lld
    ",ans);
        }
        
    }
    

     欢迎来原博客看看>原文链接<

     特别感谢同届神犇@fcwww 给我的帮助

  • 相关阅读:
    使用Areas分离ASP.NET MVC项目
    将json转化为model
    简单的三层asp.net webForm使用Ninject实现Ioc
    本机连接虚拟机Oracle时报错的解决办法
    老电脑升级
    安装Oracle时选择桌面类和服务器类的区别
    64位操作系统下启用32位模式
    log4net在WinForm和ASP.net下的设置
    Delphi2009下编译提示“无法找到“Excel_TLB”
    Delphi 中的MD5实现方法(转)
  • 原文地址:https://www.cnblogs.com/Tobichi/p/9168636.html
Copyright © 2020-2023  润新知