数论专项测试——约数个数和(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[maxn],prim[maxn],mu[maxn];
11 bool vis[maxn];
12 int64 n,f[maxn],ans;
13 void prepare(){
14     tot=top=0,memset(vis,1,sizeof(vis)),mu[0]=0,mu[1]=1,f[1]=1;
15     for (int i=2;i<maxn;i++){
16         if (vis[i]==1){
17             prim[++top]=i;
18             d[i]=i;
19             mu[i]=-1;
20             f[i]=2;
21         }
22         for (int j=1;j<=top;j++){
23             if (i*prim[j]>=maxn) break;
24             vis[i*prim[j]]=0;
25             if (i%prim[j]==0){
26                 d[i*prim[j]]=d[i]*prim[j];
27                 mu[i*prim[j]]=0;
28                 f[i*prim[j]]=f[i/d[i]]*(f[d[i]]+1);
29                 break;
30             }else{
31                 d[i*prim[j]]=prim[j];
32                 mu[i*prim[j]]=mu[i]*mu[prim[j]];
33                 f[i*prim[j]]=f[i]*f[prim[j]];
34             }
35         }
36     }
37     for (int i=2;i<maxn;i++) mu[i]+=mu[i-1];
38     for (int i=2;i<maxn;i++) f[i]=(f[i-1]+f[i])%mod;
39 }
40 #define maxp 100007
41 #define maxm 4000005
42 int now[maxp],prep[maxm];
43 int64 val[maxm],id[maxm];
44 void insert(int x,int64 y){
45     int pos=x%maxp;
46     prep[++tot]=now[pos],now[pos]=tot,val[tot]=y,id[tot]=x;
47 }
48 int64 find(int x){
49     int pos=x%maxp;
50     for (int i=now[pos];i;i=prep[i]){
51         if (id[i]==x) return val[i];
52     }
53     return -1;
54 }
55 int64 Mu(int x){
56     if (x<maxn) return mu[x];
57     int64 temp=find(x),t;
58     if (temp!=-1) return temp;
59     temp=1;
60     for (int j,i=2;i<=x;i=j+1){
61         j=x/(x/i);  t=Mu(x/i);
62         temp=((temp-1LL*(j-i+1)*t%mod)%mod+mod)%mod;
63     }
64     insert(x,temp); return temp;
65 }
66 int64 F(int x){
67     if (x<maxn) return f[x];
68     int64 temp=0;
69     for (int j,i=1;i<=x;i=j+1){
70         j=x/(x/i);
71         temp=(temp+1LL*(x/i)*(j-i+1)%mod)%mod;
72     }
73     return temp%mod;
74 }
75 int main(){
76     int64 temp;
77     prepare();
78     scanf("%lld",&n);
79     ans=0;
80     for (int j,i=1;i<=n;i=j+1){
81         j=n/(n/i); temp=F(n/i);
82         ans=(ans+1LL*(Mu(j)-Mu(i-1))%mod*temp%mod*temp%mod)%mod;
83     }
84     printf("%lld\n",(ans%mod+mod)%mod);
85     return 0;
86 }

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=4176

题目大意:

 答案对10^9+7取模。  1<=n<=10^9,单组询问。

吐槽:这是一个对我来说启发很大的题,加深了我对杜教筛的理解。

做法:式子不好写,还是用图好了。

然后用莫比乌斯反演继续化简:

这样就好办了,floor(n/k)最多只有O(sqrt(n))级别的取值,维护mu的前缀和?没错,既然不能预处理,那我们就杜教筛,F数组呢,没错,F[i]=sigam(i/j),1<=j<=i,可以sqrt(n)级别的复杂度做出,如果我们尽可能多的预处理出mu和F,那么可以把总复杂度降至O(n^(2/3)),足以过此题。

时间: 2024-12-12 06:46:35

数论专项测试——约数个数和(lucas的数论)的相关文章

hdu 4542 数论 + 约数个数相关 腾讯编程马拉松复赛

题目:http://acm.hdu.edu.cn/showproblem.php?pid=4542 小明系列故事--未知剩余系 Time Limit: 500/200 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others) Total Submission(s): 889    Accepted Submission(s): 207 Problem Description "今有物不知其数,三三数之有二,五五数之有三,七七数之有

数论线性筛总结 (素数筛,欧拉函数筛,莫比乌斯函数筛,前n个数的约数个数筛)

线性筛 线性筛在数论中起着至关重要的作用,可以大大降低求解一些问题的时间复杂度,使用线性筛有个前提(除了素数筛)所求函数必须是数论上定义的积性函数,即对于正整数n的一个算术函数 f(n),若f(1)=1,且当a,b互质时f(ab)=f(a)f(b),在数论上就称它为积性函数,若a,b不互质也满足的话则称作完全积性函数,下面说明每个筛子是怎么筛的. 最基础的是素数筛,其它三个筛都是以素数筛为前提 素数筛 void get_prime() { int pnum = 0; for(int i = 2;

(寒假练习 AcWing 870)约数个数(数论)

原题链接(戳我-) 题目描述 给定n个正整数ai,请你输出这些数的乘积的约数个数,答案对109+7取模. 输入格式 第一行包含整数n. 接下来n行,每行包含一个整数ai. 输出格式 输出一个整数,表示所给正整数的乘积的约数个数,答案需对109+7取模. 数据范围 $ 1≤n≤100,$ \(1≤ai≤2?10^9\) 输入样例: 3 2 6 8 输出样例: 12 解题思路 根据算数的进本定理可知任何一个大于1的自然数N,如果N不为质数,那么N可以唯一分解成有限个质数的乘积 \(N=P_1^{a_

最大约数个数算法分析

   最大约数个数算法分析   实验问题描述 正整数x的约数是能整除x的正整数.正整数x的约数个数记为div(x),例如,1,2,5,10都是正整数10的约数,且div(10)=4.设a和b是2个正整数,a<=b,找出a和b当中约数个数最多的数x,输出其约数个数值.   实验目的 本次实验通过利用数论知识,建立素数表,弥补累除法在时间复杂度上的缺陷,同时又结合累除法在小范围内能够计算出最准确的约数个数的特性, 在时间复杂度上获得最大的优化.   实验知识准备过程 累除法的基本思想:计算正整数a的

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

【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

hdoj 1492 The number of divisors(约数) about Humble Numbers 【数论】【质因子分解 求和】

定理:一个正整数 n 可以用素因子唯一表示为 p1^r1 * p2^r2 * ... pk^rk (其中 pi 为素数) , 那么这个数的因子的个数就是,(r1+1)*(r2+1)*...*(rk+1). 理解:为什么是加1之后再相乘,因为一个数的的因子数至少为1和他自身,但因为r1,r2..可以为0,所以因子的个数为(r1+1)... 拓展一下: 定理1: 一个正整数 n 可以用素因子唯一表示为 p1^r1 * p2^r2 * ... pk^rk (其中 pi 为素数) , 那么这个数的因子的

【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