Lucas的数论:杜教筛,莫比乌斯反演
Description:
求$\sum\limits_{i=1}^{n} \sum\limits_{j=1}^{n} d(i \times j)$
$d(i)$表示$i$的约数个数和。$n \leq 10^9$
废话:
好久没有做反演了感觉自己都不会了。。。
做了一遍发现自己真的不会了
手推了不知道多久终于推出了式子中间还错了一遍打了一半发现过不去样例
题解:
标签都知道了那也就没什么好说的了,直接上式子(类比《约数个数和》那道题)(以下分数皆表示整除向下取整)
$\sum\limits_{i=1}^{n} \sum\limits_{j=1}^{n} d(i \times j)$
$=\sum\limits_{i=1}^{n} \sum\limits_{j=1}^{n} \sum\limits_{a|i} \sum\limits_{b|j} [gcd(a,b)==1] $
$=\sum\limits_{i=1}^{n} \sum\limits_{j=1}^{n} \sum\limits_{a|i} \sum\limits_{b|j} \sum\limits_{d|a \ and \ d|b} \mu (d) $
$=\sum\limits_{d=1}^{n} \mu (d) \sum\limits_{a=1}^{\frac{n}{d}} \sum\limits_{b=1}^{\frac{n}{d}} \frac{\frac{n}{d}}{a} \frac{\frac{n}{d}}{b}$
$=\sum\limits_{d=1}^{n} \mu (d) (\sum\limits_{i=1}^{\frac{n}{d}} \frac{\frac{n}{d}}{i})^2$
然后第二个$\sum$后面的东西视作函数$f(\frac{n}{d})$,可以整除分块,前面就是杜教筛得到$\mu$的前缀和
然后函数$f(\frac{n}{d})$的求值其实也就是一个整除分块。
其实$f(x)=\sum\limits_{i=1}^{x} d(i)$即$\sum\limits_{i=1}^{x} d(i) =\sum\limits_{i=1}^{x} \frac{x}{i}$
这里的$d(x)$函数也是约数个数的意思。%%%LrefraiNC
从含义上也可以理解。所以$f(x)$函数也可以杜教筛。但是我还没有做过$d(i)$的杜教筛所以我没有打。
杜教筛线筛预处理的范围应该在$n^{\frac{2}{3}}=10^6$不然慢的要死(虽说没有T)
1 #include<cstdio> 2 #define mod 1000000007 3 struct hash_map{ 4 int w[10000005],fir[3000005],l[10000005],to[10000005],cnt; 5 int &operator[](int x){ 6 int r=x%3000001; 7 for(int i=fir[r];i;i=l[i])if(to[i]==x)return w[i]; 8 l[++cnt]=fir[r];fir[r]=cnt;to[cnt]=x;return w[cnt]=-123456789; 9 } 10 }M; 11 int p[1000005],mu[1000005],pc;char np[1000005]; 12 int sum(int n){ 13 if(n<=1000000)return mu[n]; 14 if(M[n]!=-123456789)return M[n]; 15 int a=1; 16 for(int l=2,r,A;l<=n;l=r+1)A=n/l,r=n/A,a-=sum(A)*(r-l+1); 17 return M[n]=a; 18 } 19 long long cal(int x,long long ans=0){ 20 for(int l=1,r,a;l<=x;l=r+1)a=x/l,r=x/a,ans=(ans+a*(r-l+1ll))%mod; 21 return ans*ans%mod; 22 } 23 int main(){ 24 mu[1]=1; 25 for(int i=2;i<=1000000;++i){ 26 if(!np[i])p[++pc]=i,mu[i]=-1; 27 for(int j=1;j<=pc&&i*p[j]<=1000000;++j) 28 if(i%p[j])mu[i*p[j]]=-mu[i],np[i*p[j]]=-1; 29 else np[i*p[j]]=-1; 30 mu[i]+=mu[i-1]; 31 } 32 int n;long long ans=0;scanf("%d",&n); 33 for(int l=1,r,a;l<=n;l=r+1)a=n/l,r=n/a,ans+=1ll*cal(a)*(sum(r)-sum(l-1))%mod; 34 printf("%lld\n",(ans%mod+mod)%mod); 35 }