BZOJ_4176_Lucas的数论_杜教筛+莫比乌斯反演
BZOJ_4176_Lucas的数论_杜教筛+莫比乌斯反演
Description
去年的Lucas非常喜欢数论题,但是一年以后的Lucas却不那么喜欢了。

Input
第一行一个整数n。
Output
一行一个整数ans,表示答案模1000000007的值。
Sample Input
Sample Output
HINT
对于100%的数据n <= 10^9。
f(nm)=∑i|n∑j|m[gcd(i,j)=1]
证明:首先ij|nm,但直接枚举ij会有些重复。
设gcd(i,j)=k,a=i/k,b=j/k
发现一定能枚举到i′=a∗k,j′=b,和i″,此时gcd(i',j')=gcd(i'',j'')=1。
考虑a*b*k这个约数其实是被枚举了两次,不妨用这两次中的一个来‘代表’a*b*k*k。
因此我们枚举gcd(i,j)=1的i,j即可,只是此时ij可能有相等的,他们代表的约数不同。
可以举n=2,m=6的例子自己手算一下。
\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{n}f(ij) = \sum\limits_{i=1}^{n}\sum\limits_{j=1}^{n}\sum \limits_{x|i}\sum\limits_{y|j}[gcd(x,y)=1]
=\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{n}\sum \limits_{x|i}\sum\limits_{y|j}\sum\limits_{d|gcd(x,y)}\mu(d)
=\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{n}\sum \limits_{x|i}\sum\limits_{y|j}\sum\limits_{d|gcd(x,y)}\mu(d)
=\sum\limits_{d=1}^{n}\mu(d)\sum\limits_{i=1}^{n/d}\sum\limits_{j=1}^{n/d}\sum \limits_{x=1}^{\frac{n/d}{i}}\sum\limits_{y=1}^{\frac{n/d}{j}}
=\sum\limits_{d=1}^{n}\mu(d)(\sum\limits_{i=1}^{n/d}\frac{n/d}{i})^{2}
\mu的前缀和用杜教筛搞,后面的只有\sqrt{n/d}种取值。
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | #include <stdio.h> #include <string.h> #include <algorithm> #include <map> using namespace std; typedef long long ll; ll mod=1000000007; map<ll,ll>f; int m=1000000; int prime[1000050],cnt,miu[1000050],summiu[1000050]; bool vis[1000050]; ll calc1(ll n) { if (n<=m) return summiu[n]; if (f.count(n)) return f[n]; ll i,lst,ans=1; for (i=2;i<=n;i=lst+1) { lst=n/(n/i); ans=(ans-(lst-i+1)*calc1(n/i)%mod+mod)%mod; } return f[n]=ans; } ll calc2(ll n) { ll ans=0,i,lst; for (i=1;i<=n;i=lst+1) { lst=n/(n/i); ans=(ans+n/i*(lst-i+1))%mod; } return ans*ans%mod; } void init() { int i,j; miu[1]=summiu[1]=1; for (i=2;i<=m;i++) { if (!vis[i]) { prime[++cnt]=i; miu[i]=-1; } for (j=1;j<=cnt&&i*prime[j]<=m;j++) { vis[i*prime[j]]=1; if (i%prime[j]==0) { miu[i*prime[j]]=0; break ; } miu[i*prime[j]]=-miu[i]; } summiu[i]=summiu[i-1]+miu[i]; } } int main() { init(); ll n,ans=0,i,lst; scanf ( "%lld" ,&n); for (i=1;i<=n;i=lst+1) { lst=n/(n/i); ans=(ans+(calc1(lst)-calc1(i-1)+mod)%mod*calc2(n/i))%mod; } printf ( "%lld\n" ,ans); } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】凌霞软件回馈社区,携手博客园推出1Panel与Halo联合会员
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步