zoukankan      html  css  js  c++  java
  • 51nod1238 最小公倍数之和 V3

    n<=1e10,求1<=i<=n,1<=j<=n,lcm(i,j)的和。

    又是充满坎坷的简单题。。。

    Wait a minute 先打个miu和phi的表,以及一个暴力,随时检查式子!

    来吧!

    $sum_{i=1}^{n}sum_{j=1}^{n}[i,j]$

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

    $=sum_{d=1}^{n}d^{-1}sum_{i=1}^{n}sum_{j=1}^{n}ij[(i,j)=d]$

    停住!

    这里是一个重要抉择,后面怎么变换直接决定了做出这题的难度以及代码复杂度!!!

    一、直接反演

    $=sum_{d=1}^{n}d^{-1}sum_{d|t,tleqslant n}mu (frac{t}{d})t^2(frac{(1+left lfloor frac{n}{t} ight floor)left lfloor frac{n}{t} ight floor}{2})^2$

    $=sum_{t=1}^{n}t^2(frac{(1+left lfloor frac{n}{t} ight floor)left lfloor frac{n}{t} ight floor}{2})^2sum_{d|t}d^{-1}mu(frac{t}{d})$

    闪一句:两个t丢后面。

    $=sum_{t=1}^{n}(frac{(1+left lfloor frac{n}{t} ight floor)left lfloor frac{n}{t} ight floor}{2})^2(tsum_{d|t}dmu(d))$

    需要求后面那堆的前缀和。转移战线:

    $sum_{t=1}^{n}tsum_{d|t}dmu(d)$

    $=sum_{t=1}^{n}sum_{d|t}tdmu(d)$

    $=sum_{k=1}^{n}sum_{d=1}^{left lfloor frac{n}{k} ight floor}kd^2mu(d)$

    $=sum_{d=1}^{n}d^2mu(d)sum_{k=1}^{left lfloor frac{n}{d} ight floor}k$

    $=sum_{d=1}^{n}(frac{(1+left lfloor frac{n}{d} ight floor)left lfloor frac{n}{d} ight floor}{2})d^2mu(d)$

    好的!只需要一个$d^2mu(d)$的前缀和即可。配俩Id(x)=x给他卷积:

    $sum_{i=1}^{n}sum_{d|i}d^2mu(d)(frac{i}{d})^2$

    $=sum_{k=1}^{n}k^2sum_{d=1}^{left lfloor frac{i}{k} ight floor}d^2mu(d)$

    于是$sum_{i=1}^{n}i^2mu(i)=1-sum_{k=2}^{n}k^2sum_{i=1}^{left lfloor frac{n}{k} ight floor}d^2mu(d)$

    套了若干个,还是$n^{frac{2}{3}}$。但这代码量就。。

    二、反演个鬼

    $sum_{d=1}^{n}d^{-1}sum_{i=1}^{n}sum_{j=1}^{n}ij[(i,j)=d]$

    $=sum_{d=1}^{n}dsum_{i=1}^{left lfloor frac{n}{d} ight floor}sum_{j=1}^{left lfloor frac{n}{d} ight floor}ij[(i,j)=1]$

    $=sum_{d=1}^{n}d((2sum_{i=1}^{left lfloor frac{n}{d} ight floor}isum_{j=1}^{i}j[(i,j)=1])-1)$

    $=sum_{d=1}^{n}d((2sum_{i=1}^{left lfloor frac{n}{d} ight floor}ifrac{ivarphi(i)+[i=1]}{2})-1)$

    $=sum_{d=1}^{n}d((sum_{i=1}^{left lfloor frac{n}{d} ight floor}i^2varphi(i)+[i=1])-1)$

    $=sum_{d=1}^{n}dsum_{i=1}^{left lfloor frac{n}{d} ight floor}i^2varphi(i)$

    接着就是$i^2varphi(i)$的前缀和啦!一样丢俩Id(x)=x给他卷积:

    $sum_{i=1}^{n}sum_{d|i}d^2varphi(d)(frac{i}{d})^2$

    $=sum_{k=1}^{n}k^2sum_{d=1}^{left lfloor frac{n}{k} ight floor}d^2varphi(d)$

    得$sum_{i=1}^{n}i^2varphi(i)=(frac{n(n+1)}{2})^2-sum_{k=2}^{n}k^2sum_{i=1}^{left lfloor frac{n}{k} ight floor}i^2varphi(i)$

    大功告成。

    首先从正确性来说的话,以后一定要先打好表和暴力再来推,推两句检查一次。因为一半有推的人都可以推到类似nln(n)的复杂度,就算最后推不出正解,较多的暴力还是可以拿到的。

    然后多尝试把不同的东西提出来,不要怕失败。

    至于说这题两种不同的推法得到了两种时间相同但编码复杂度差别较大的方法,我认为是在学数论初期是难免的。多总结多锻炼也许就能少走弯路。

     1 #include<string.h>
     2 #include<stdlib.h>
     3 #include<stdio.h>
     4 #include<math.h>
     5 //#include<assert.h>
     6 #include<algorithm> 
     7 //#include<iostream>
     8 //#include<bitset>
     9 using namespace std;
    10 
    11 #define LL long long
    12 LL n,m;
    13 #define maxn 5000011
    14 const int mod=1e9+7;
    15 int phi[maxn],sumphi[maxn],prime[maxn],lp; bool notprime[maxn];
    16 
    17 void pre(int n)
    18 {
    19     phi[1]=1; sumphi[1]=1;
    20     for (int i=2;i<=n;i++)
    21     {
    22         if (!notprime[i]) {prime[++lp]=i; phi[i]=i-1;}
    23         sumphi[i]=sumphi[i-1]+1ll*i*i%mod*phi[i]%mod;
    24         sumphi[i]-=sumphi[i]>=mod?mod:0;
    25         for (int tmp,j=1;j<=lp && 1ll*prime[j]*i<=n;j++)
    26         {
    27             notprime[tmp=prime[j]*i]=1;
    28             if (i%prime[j]) phi[tmp]=phi[i]*(prime[j]-1);
    29             else {phi[tmp]=phi[i]*prime[j]; break;}
    30         }
    31     }
    32 }
    33 
    34 struct Edge{LL to; int v,next;};
    35 #define maxh 1000007
    36 struct Hash
    37 {
    38     int first[maxh],le; Edge edge[maxn];
    39     Hash() {le=2;}
    40     void insert(LL y,int v) {int x=y%maxh; Edge &e=edge[le]; e.to=y; e.v=v; e.next=first[x]; first[x]=le++;}
    41     int find(LL y) {int x=y%maxh; for (int i=first[x];i;i=edge[i].next) if (edge[i].to==y) return edge[i].v; return -1;}
    42 }h;
    43 
    44 int two=(mod+1)/2,six=(mod+1)/6;
    45 int calc(LL n)
    46 {
    47     if (n<=m) return sumphi[n];
    48     int tmp=h.find(n); if (tmp!=-1) return tmp;
    49     int ans=(n%mod)%mod*((n+1)%mod)%mod*(n%mod)%mod*((n+1)%mod)%mod*two%mod*two%mod;
    50     for (LL i=2,last;i<=n;i=last+1)
    51     {
    52         last=n/(n/i);
    53         ans-=((last%mod)%mod*((last+1)%mod)%mod*((last+last+1)%mod)%mod*six%mod
    54         -((i-1)%mod)%mod*(i%mod)%mod*((i+i-1)%mod)%mod*six%mod)*calc(n/i)%mod;
    55         ans+=ans<0?mod:0; ans-=ans>=mod?mod:0;
    56     }
    57     h.insert(n,ans);
    58     return ans;
    59 }
    60 
    61 int main()
    62 {
    63     scanf("%lld",&n);
    64     m=pow(n,2.0/3); pre(m);
    65     int ans=0;
    66     for (LL i=1,last;i<=n;i=last+1)
    67     {
    68         last=n/(n/i);
    69         ans+=((last-i+1)%mod)*((last+i)%mod)%mod*two%mod*calc(n/i)%mod;
    70         ans-=ans>=mod?mod:0;
    71     }
    72     printf("%d
    ",ans);
    73     return 0;
    74 }
    View Code
  • 相关阅读:
    c++11 static_assert
    UVA
    析构函数与运行错误
    UVA
    2017 ACM-ICPC 亚洲区(乌鲁木齐赛区) C. Coconut
    2017 ACM-ICPC 亚洲区(乌鲁木齐赛区) A. Banana
    DOCTYPE的作用?
    数组去重的方法
    闭包的分析?
    SVN(集中式管理)分析
  • 原文地址:https://www.cnblogs.com/Blue233333/p/8320009.html
Copyright © 2011-2022 走看看