BZOJ 4176 Lucas的数论 莫比乌斯反演+杜教筛

题意概述:求,n<=10^9,其中d(n)表示n的约数个数。

 

分析:

  首先想要快速计算上面的柿子就要先把d(ij)表示出来,有个神奇的结论:

  

  证明:当且仅当a,b没有相同的质因数的时候我们统计其贡献,可以发现所有被统计的(a,b)乘积的质因数分解形式正好和i,j的所有因数的质因数分解形式一一对应,不重不漏(对于b中质因数指数不为0对应的就是i中指数+b中指数的情况,对于b中质因数指数为0的情况对应i中指数的情况)。

  然后就有如下的推导:

  

 

  对于这个式子,整个数字分段来算,n/d一共sqrt(n)种取值,用杜教筛求μ的前缀和,后面那部分每次可以用sqrt(n/d)的复杂度计算出来,整个时间复杂度大约是O(n^(3/4))。(实在是太玄学了这个时间复杂度我不是很会算ORZ)

 

  至于杜教筛......这里我就不讲了吧,看dalao链接!:http://jiruyi910387714.is-programmer.com/posts/195270.html

 

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cstdlib>
 5 #include<algorithm>
 6 #include<cmath>
 7 #include<queue>
 8 #include<set>
 9 #include<map>
10 #include<vector>
11 #include<cctype>
12 using namespace std;
13 const int mo=1000000007;
14 const int maxn=1000005;
15 
16 int N,pri[maxn],mu[maxn],tot;
17 bool ntp[maxn];
18 struct Hash{
19     static const int sz=3000007;
20     static const int maxn=10000005;
21     int first[sz],np,next[maxn],id[maxn],val[maxn];
22     Hash(){
23         np=0;
24         memset(first,0,sizeof(first));
25     }
26     void ins(int pos,int v){
27         int i=pos%sz;
28         next[++np]=first[i],first[i]=np;
29         id[np]=pos,val[np]=v;
30     }
31     int query(int pos){
32         int i=pos%sz;
33         for(int p=first[i];p;p=next[p])
34             if(id[p]==pos) return val[p];
35         return -1;
36     }
37 }hash;
38 
39 void get_mu()
40 {
41     ntp[0]=ntp[1]=1,mu[1]=1;
42     for(int i=2;i<=1000000;i++){
43         if(!ntp[i]) pri[++tot]=i,mu[i]=-1;
44         for(int j=1;j<=tot&&1ll*pri[j]*i<=1000000;j++){
45             ntp[i*pri[j]]=1;
46             if(i%pri[j]==0){ mu[pri[j]*i]=0; break; }
47             mu[pri[j]*i]=-mu[i];
48         }
49     }
50 }
51 int F(int n){
52     int re=0;
53     for(int i=1,last;i<=n;i=last+1)
54         last=n/(n/i),re=(re+1ll*(last-i+1)*(n/i)%mo)%mo;
55     return re;
56 }
57 int S(int n){
58     int re=hash.query(n);
59     if(re!=-1) return re;
60     re=1;
61     for(int i=2,last;i<=n;i=last+1){
62         last=n/(n/i);
63         re=(re-1ll*(last-i+1)*S(n/i)%mo+mo)%mo;
64     }
65     hash.ins(n,re);
66     return re;
67 }
68 int solve(int n)
69 {
70     int re=0,f;
71     for(int i=1,last;i<=n;i=last+1){
72         last=n/(n/i),f=F(n/i);
73         re=(re+1ll*f*f%mo*(S(last)-S(i-1)+mo)%mo)%mo;
74     }
75     return re;
76 }
77 int main()
78 {
79     get_mu();
80     int sum=0;
81     for(int i=0;i<=1000000;i++)
82         hash.ins(i,sum=(sum+mu[i]+mo)%mo);
83     scanf("%d",&N);
84     printf("%d\n",solve(N));
85     return 0;
86 }
View Code

 

posted @ 2018-04-04 15:14  KKKorange  阅读(261)  评论(0编辑  收藏  举报