Description
去年的Lucas非常喜欢数论题,但是一年以后的Lucas却不那么喜欢了。
在整理以前的试题时,发现了这样一道题目“求Sigma(f(i)),其中1<=i<=N”,其中 表示i的约数个数。他现在长大了,题目也变难了。
求如下表达式的值:
\[
\sum_{i=1}^n\sum_{j=1}^nf(ij)
\]
其中 表示ij的约数个数。
他发现答案有点大,只需要输出模1000000007的值。
Input
第一行一个整数n。
Output
一行一个整数ans,表示答案模1000000007的值。
Sample Input
2
Sample Output
8
HINT
对于100%的数据n <= 10^9。
solution
这题要求的东西其实和[bzoj3994] [SDOI2015]约数个数和是一样的,只是数据范围不同.
由于这题\(n\)到了\(1e9\),考虑使用杜教筛.
对于\(f(n)=\sum_{i=1}^{n}\lfloor\frac{n}{i}\rfloor\),可以数论分块大力算一下.
然后考虑\(\sum_{i=1}^{n}\mu(i)\)怎么算.
先把杜教筛的套路式搬出来:
\[
S(n)=\sum_{i=1}^{n}(f*g)(i)-\sum_{i=2}^{n}g(i)S(\lfloor\frac{n}{i}\rfloor)
\]
其中,设\(f(n)=\mu(n)\),\(S(n)=\sum_{i=1}^nf(i)\).
然后我们知道这样一个式子:
\[
\sum_{d|n}\mu(d)=\epsilon(n)
\]
其中\(\epsilon(n)=[n=1]\),表示狄利克雷卷积的元函数.
所以我们令\(g(n)=1\),即常函数,然后卷起来:
\[
(f*g)(n)=\sum_{d|n}f(d)g(\frac{n}{d})=\sum_{d|n}\mu(d)=\epsilon(n)
\]
所以\(\sum_{i=1}^{n}(f*g)(i)=1\),即:
\[
S(n)=1-\sum_{i=2}^{n}S(\lfloor\frac{n}{i}\rfloor)
\]
然后递归求解,线筛出前\(1e7\)个,记忆化一下就做完了.
#include<bits/stdc++.h> using namespace std; #define int long long void read(int &x) { x=0;int f=1;char ch=getchar(); for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f; for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f; } void print(int x) { if(x<0) x=-x,putchar('-'); if(!x) return ;print(x/10),putchar(x%10+48); } void write(int x) {if(!x) putchar('0');else print(x);putchar('\n');} const int maxn = 1e7+1; const int mod = 1e9+7; int pri[maxn],vis[maxn],mu[maxn],n,tot; void sieve() { mu[1]=1; for(int i=2;i<maxn;i++) { if(!vis[i]) pri[++tot]=i,mu[i]=-1; for(int t,j=1;j<=tot&&i*pri[j]<maxn;j++) { vis[t=i*pri[j]]=1; if(!(i%pri[j])) {mu[t]=0;break;} mu[t]=-mu[i]; } } for(int i=1;i<maxn;i++) mu[i]=(mu[i-1]+mu[i])%mod; } map<int,int > Sum_mu; int sum_mu(int n) { if(n<maxn) return mu[n]; if(Sum_mu[n]) return Sum_mu[n]; int T=2,res=1; while(T<=n) { int pre=T;T=n/(n/T); res=(res-(T-pre+1)*sum_mu(n/T))%mod;T++; } return Sum_mu[n]=(res%mod+mod)%mod; } int calc(int n) { int T=1,res=0; while(T<=n) { int pre=T;T=n/(n/T); res=(res+(T-pre+1)*(n/T))%mod;T++; } return res; } signed main() { sieve(); int n;read(n); int T=1,ans=0; while(T<=n) { int pre=T;T=n/(n/T);int r=calc(n/T); ans=(ans+(sum_mu(T)-sum_mu(pre-1))*r%mod*r%mod)%mod;T++; } write((ans%mod+mod)%mod); return 0; }
来源:https://www.cnblogs.com/hbyer/p/10072917.html