题链:
http://acm.hdu.edu.cn/showproblem.php?pid=5608
题解:
莫比乌斯反演,杜教筛
已知$$N^2-3N+2=\sum_{d|N} f(d)$$
多次询问,给出n,求f的前缀和S(n)。
把f函数卷上$I(x)=1$
那么有:
$$\sum_{i=1}^{n}f*l(i)=\sum_{i=1}^{n}l(i)S(\lfloor \frac{n}{i} \rfloor)$$
所以:
$$S(n)=\sum_{i=1}^{n}f*l(i)-\sum_{i=2}^{n}S(\lfloor \frac{n}{i} \rfloor)$$
又因为
$$\begin{aligned}
\sum_{i=1}^{n}f*l(i)&=\sum_{i=1}^{n}\sum_{d|i}f(d)l(\frac{i}{d})\\
&=\sum_{i=1}^{n}\sum_{d|i}f(d)\\
&=\sum_{i=1}^{n}(i^2-3i+2)\\
&=\frac{n(n+1)(2n+1)}{6}-\frac{3n(1+n)}{2}+2n\\
\end{aligned}$$
所以
$$S(n)=\frac{n(n+1)(2n+1)}{6}-\frac{3n(1+n)}{2}+2n-\sum_{i=2}^{n}S(\lfloor \frac{n}{i} \rfloor)$$
到此,就可以直接用杜教筛求解了,不过有点慢。
我们可以先预处理出前$n^{\frac{2}{3}}$个的前缀和
令$F(N)=N^2-3N+2$,那么F就是f的约数和函数
(因为$F(N)=\sum_{d|N}f(d)$)
所以由莫比乌斯反演可知:
$$f(N)=\sum_{d|N}\mu(d)F(\frac{N}{d})$$
然后可以用$O(nlogn)$的复杂度先处理出一些前缀和,
然后再杜教筛即可。
代码:
#include<bits/stdc++.h> #define DJM 1000000 using namespace std; const int mod=1000000007; struct Hash_Table{ #define Hmod 1425367 int org[DJM+50],val[DJM+50],nxt[DJM+50],head[Hmod],hnt; Hash_Table(){hnt=1;} void Push(int x,int v){ static int u; u=x%Hmod; org[hnt]=x; val[hnt]=v; nxt[hnt]=head[u]; head[u]=hnt++; } int Find(int x){ static int u; u=x%Hmod; for(int i=head[u];i;i=nxt[i]) if(org[i]==x) return val[i]; return -1; } }H; int mu[DJM+50],F[DJM+50],f[DJM+50]; void Sieve(){ static bool np[DJM+50]; static int prime[DJM+50],pnt; mu[1]=1; for(int i=2;i<=DJM;i++){ F[i]=(1ll*i*i-3*i+2+mod)%mod; if(!np[i]) prime[++pnt]=i,mu[i]=-1; for(int j=1;j<=pnt&&i<=DJM/prime[j];j++){ np[i*prime[j]]=1; if(i%prime[j]) mu[i*prime[j]]=-mu[i]; else break; } } for(int d=1;d<=DJM;d++) for(int i=1;i*d<=DJM;i++) f[i*d]=(1ll*f[i*d]+1ll*mu[d]*F[i]%mod+mod)%mod; for(int i=1;i<=DJM;i++) f[i]=(1ll*f[i]+f[i-1])%mod; } int DJ_pf(int n){ static int inv6=166666668; if(n<=DJM) return f[n]; if(H.Find(n)!=-1) return H.Find(n); int ret=(1ll*n*(n+1)%mod*(2*n+1)%mod*inv6%mod-3ll*(1+n)*n/2%mod+2ll*n%mod+mod)%mod; for(int i=2,last;i<=n;i=last+1){ last=n/(n/i); ret=(1ll*ret-1ll*(last-i+1)*DJ_pf(n/i)%mod+mod)%mod; } H.Push(n,ret); return ret; } int main(){ Sieve(); int Case,n; for(scanf("%d",&Case);Case;Case--){ scanf("%d",&n); printf("%d\n",DJ_pf(n)); } return 0; }
原文地址:https://www.cnblogs.com/zj75211/p/8316203.html