Bzoj4176 Lucas的数论

Description

去年的Lucas非常喜欢数论题,但是一年以后的Lucas却不那么喜欢了。

在整理以前的试题时,发现了这样一道题目“求Sigma(f(i)),其中1<=i<=N”,其中 表示i的约数个数。他现在长大了,题目也变难了。

求如下表达式的值:

其中 表示ij的约数个数。

他发现答案有点大,只需要输出模1000000007的值。

Input

第一行一个整数n。

Output

一行一个整数ans,表示答案模1000000007的值。

Sample Input

2

Sample Output

8

HINT

对于100%的数据n <= 10^9。

数学问题 莫比乌斯反演 脑洞题

$ans(n)=\sum_{i=1}^{n} \sum_{j=1}^{n} f(i,j)$
$=\sum_{i=1}^{n} \sum_{j=1}^{n} \sum_{k=1}^{n^2} [\frac{k}{gcd(i,j)}|j]$
(枚举gcd)
$=\sum_{d=1}^{n} d \sum_{i=1}^{\lfloor \frac{n}{d} \rfloor}\sum_{j=1}^{\lfloor \frac{n}{d} \rfloor}\sum_{k=1}^{\lfloor \frac{n^2}{d} \rfloor} [k|j][gcd(k,i)=1] $
(消掉j)
$=\sum_{d=1}^{n} d \sum_{i=1}^{\lfloor \frac{n}{d} \rfloor}\sum_{k=1}^{\lfloor \frac{n^2}{d} \rfloor} d \lfloor \frac{n}{dk} \rfloor [gcd(k,i)=1] $
(约掉一个d)
$=\sum_{d=1}^{n} \sum_{i=1}^{\lfloor \frac{n}{d} \rfloor}\sum_{k=1}^{\lfloor \frac{n^2}{d} \rfloor} \lfloor \frac{n}{k} \rfloor [gcd(k,i)=1] $

$=\sum_{d=1}^{n} \sum_{i=1}^{\lfloor \frac{n}{d} \rfloor}\sum_{k=1}^{\lfloor \frac{n^2}{d} \rfloor} \lfloor \frac{n}{k} \rfloor \sum_{t|(ik)} \mu(t)$

$= \sum_{t=1}^{1} \mu(t) \sum_{d=1}^{n} \sum_{i=1}^{\lfloor \frac{n}{dt} \rfloor}\sum_{k=1}^{\lfloor \frac{n^2}{dt} \rfloor} \lfloor \frac{n}{kt} \rfloor$
(注意到i对后面没有影响,把求和变为乘)
$= \sum_{t=1}^{1} \mu(t) \sum_{d=1}^{n} \lfloor \frac{n}{dt} \rfloor\sum_{k=1}^{\lfloor \frac{n^2}{dt} \rfloor} \lfloor \frac{n}{kt} \rfloor$
(注意到d在大于$ \lfloor \frac{n}{t} \rfloor$ 时,后面全是0,所以缩小求和上界,后面的k同理)
$= \sum_{t=1}^{1} \mu(t) \sum_{d=1}^{\lfloor \frac{n}{t} \rfloor} \lfloor \frac{n}{dt} \rfloor\sum_{k=1}^{\lfloor \frac{n}{t} \rfloor} \lfloor \frac{n}{kt} \rfloor$

$= \sum_{t=1}^{1} \mu(t) (\sum_{d=1}^{\lfloor \frac{n}{t} \rfloor} \lfloor \frac{n}{dt} \rfloor)^2 $

$\mu$的前缀和可以用bzoj3944的方法筛出来,后面的平方项可以分块计算。
也就是说分块套分块就可以愉快地出解了。

隔壁Sfailsth告诉我可以直接用Bzoj3994的结论来做
↓也就是从这个式子开始:
$\sum_{i=1}^{N}\sum_{j=1}^{M}d(ij)=\sum_{i=1}^{N}\sum_{j=1}^{M}\lfloor\frac{N}{i}\rfloor\lfloor\frac{M}{j}\rfloor\lbrack gcd(i,j)=1 \rbrack $
确实很方便

(做完这道题之后,陪伴了我们一年的权限号过期了)

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cstring>
 4 #include<cstdio>
 5 #include<cmath>
 6 #include<map>
 7 #define LL long long
 8 using namespace std;
 9 const int mod=1e9+7;
10 const int mxn=5000010;
11 int read(){
12     int x=0,f=1;char ch=getchar();
13     while(ch<‘0‘ || ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();}
14     while(ch>=‘0‘ && ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
15     return x*f;
16 }
17 int pri[mxn],mu[mxn],cnt=0;
18 bool vis[mxn];
19 void init(){
20     mu[1]=1;
21     for(int i=2;i<mxn;i++){
22         if(!vis[i]){
23             pri[++cnt]=i;
24             mu[i]=-1;
25         }
26         for(int j=1;j<=cnt && (LL)pri[j]*i<mxn;j++){
27             int tmp=pri[j]*i;
28             vis[tmp]=1;
29             if(i%pri[j]==0){vis[tmp]=1;mu[tmp]=0;break;}
30             mu[tmp]=-mu[i];
31         }
32     }
33     for(int i=2;i<mxn;i++){mu[i]=mu[i-1]+mu[i];}
34     return;
35 }
36 map<int,LL>mpmu;
37 int F(int x){
38     if(x<mxn)return mu[x];
39     if(mpmu.count(x))return mpmu[x];
40     int res=1;
41     for(int i=2,pos;i<=x;i=pos+1){
42         int y=x/i;
43         pos=x/y;
44         res=((LL)res-(LL)(pos-i+1)*F(y)%mod+mod)%mod;
45     }
46     mpmu[x]=res;
47     return res;
48 }
49 int calc(int x){
50     int res=0;
51     for(int i=1,pos;i<=x;i=pos+1){
52         int y=x/i;
53         pos=x/y;
54         res=(res+(pos-i+1)*(LL)y%mod)%mod;
55     }
56     return (LL)res*res%mod;
57 }
58 int main(){
59     init();
60     int n=read();
61     LL ans=0;
62     for(int i=1,pos;i<=n;i=pos+1){
63         int y=n/i;pos=n/y;
64         ans=((LL)ans+(((LL)F(pos)-F(i-1)%mod))*calc(y)%mod)%mod;
65     }
66     ans=(ans%mod+mod)%mod;
67     printf("%lld\n",ans);
68     return 0;
69 }
时间: 2024-10-15 12:50:08

Bzoj4176 Lucas的数论的相关文章

bzoj4176. Lucas的数论 杜教筛

题意:求\(\sum_{i=1}^n\sum_{j=1}^nd(ij),d是约数个数函数\) 题解:首先有一个结论\(d(ij)=\sum_{x|i}\sum_{y|j}[(i,j)==1]\) 那么\(\sum_{i=1}^n\sum_{j=1}^n\sum_{x|i}\sum_{y|j}\sum_{d|(i,j)}\mu(d)\) 枚举d,\(\sum_{i=1}^n\sum_{j=1}^n\sum_{d|i,d|j}\mu(d)d(\frac{i}{d})d(\frac{j}{d})=\s

bzoj 4176 Lucas的数论

bzoj 4176 Lucas的数论 和约数个数和那题差不多.只不过那个题是多组询问,这题只询问一次,并且 \(n\) 开到了 \(10^9\). \[ \begin{align*} \sum_{i=1}^N \sum_{j=1}^N f(ij)&= \sum_{i=1}^N \sum_{j=1}^N \sum_{x|i} \sum_{y|j}[gcd(x,y)=1]\\&= \sum_{i=1}^N \sum_{j=1}^N \sum_{x|i} \sum_{y|j} \sum_{d|g

【bzoj4176】Lucas的数论 莫比乌斯反演+杜教筛

题目描述 去年的Lucas非常喜欢数论题,但是一年以后的Lucas却不那么喜欢了. 在整理以前的试题时,发现了这样一道题目“求Sigma(f(i)),其中1<=i<=N”,其中 表示i的约数个数.他现在长大了,题目也变难了. 求如下表达式的值: 其中f(ij)表示ij的约数个数. 他发现答案有点大,只需要输出模1000000007的值. 输入 第一行一个整数n. 输出 一行一个整数ans,表示答案模1000000007的值. 样例输入 2 样例输出 8 题解 莫比乌斯反演+杜教筛 首先有个神奇

【BZOJ4176】 Lucas的数论

Description 去年的Lucas非常喜欢数论题,但是一年以后的Lucas却不那么喜欢了. 在整理以前的试题时,发现了这样一道题目“求Sigma(f(i)),其中1<=i<=N”,其中 表示i的约数个数.他现在长大了,题目也变难了. 求如下表达式的值: 其中 表示ij的约数个数. 他发现答案有点大,只需要输出模1000000007的值. Input 第一行一个整数n. Output 一行一个整数ans,表示答案模1000000007的值. Sample Input 2 Sample Ou

【bzoj 4176】 Lucas的数论 莫比乌斯反演(杜教筛)

Description 去年的Lucas非常喜欢数论题,但是一年以后的Lucas却不那么喜欢了. 在整理以前的试题时,发现了这样一道题目“求Sigma(f(i)),其中1<=i<=N”,其中 表示i的约数个数.他现在长大了,题目也变难了. 求如下表达式的值: 一行一个整数ans,表示答案模1000000007的值. Sample Input 2 Sample Output 8 HINT 对于100%的数据n <= 10^9. 题解: 解锁新技能:杜教筛. 再复习一下: 若$F(n)=\s

BZOJ 4176 Lucas的数论 莫比乌斯反演

题目大意:给定n(n≤109),求∑ni=1∑nj=1d(ij) 推错式子害死人... 由d|ij等价于dgcd(i,d)|j可得 ∑ni=1∑nj=1d(ij) =∑ni=1∑n2d=1?n?gcd(i,d)d? =∑nd=1∑?nd?i=1∑?n2d?j=1?nj?[gcd(i,j)=1] =∑nd=1∑?nd?i=1∑nj=1?nj?[gcd(i,j)=1] =∑nd=1∑?nd?i=1∑nj=1?nj?∑k|i,k|jμ(k) =∑nk=1μ(k)(∑?nk?d=1?nkd?)2 O(n

数论专项测试——约数个数和(lucas的数论)

1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cmath> 5 #include <algorithm> 6 using namespace std; 7 typedef long long int64; 8 const int mod=1000000007; 9 #define maxn 2000005 10 int top,tot,d[ma

●BZOJ 4176 Lucas的数论

题链: http://www.lydsy.com/JudgeOnline/problem.php?id=4176 题解: 莫比乌斯反演,杜教筛 首先有这么一个结论: 令d(n)表示n的约数的个数(就是题目中的f(n)),则有 $$d(nm)=\sum_{i|n}\sum_{j|m}[gcd(i,j)==1]$$ ●BZOJ 3994 [SDOI2015]约数个数和也用到了这个东西. 那么就下来接直接进行求ANS的式子的推导: $$\begin{aligned}ANS&=\sum_{n=1}^{N

【算法总结】积性函数相关

[线性筛] [模板代码] [线性筛质数] 1 int main() 2 { 3 n=read(); 4 for(int i=2;i<=n;i++) 5 { 6 if(!f[i])pri[++cnt]=i; 7 for(int j=1;j<=cnt;j++) 8 { 9 if(i*pri[j]>n)break; 10 f[i*pri[j]]=1; 11 if(i%pri[j]==0)break; 12 } 13 } 14 } [线性求约数和] 1 void pre() 2 { 3 miu[