SPOJDIVCNT2: Counting Divisors(莫比乌斯反演)

http://acm.tzc.edu.cn/acmhome/vProblemList.do?method=problemdetail&oj=SPOJ&pid=DIVCNT2

给出n求

其中是除数函数,0代表0次方.

 1 #include<algorithm>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<cstring>
 5 #include<iostream>
 6 #define ll long long
 7 ll n,sig[100000005],N,a[200005];
 8 int p[10000005];
 9 bool mark[100000005];
10 char mul[100000005];
11 int smu[100000005],L;
12 int read(){
13     int t=0,f=1;char ch=getchar();
14     while (ch<‘0‘||ch>‘9‘){if (ch==‘-‘) f=-1;ch=getchar();}
15     while (‘0‘<=ch&&ch<=‘9‘){t=t*10+ch-‘0‘;ch=getchar();}
16     return t*f;
17 }
18 ll Read(){
19     ll t=0,f=1;char ch=getchar();
20     while (ch<‘0‘||ch>‘9‘){if (ch==‘-‘) f=-1;ch=getchar();}
21     while (‘0‘<=ch&&ch<=‘9‘){t=t*10+ch-‘0‘;ch=getchar();}
22     return t*f;
23 }
24 void Init(int n){
25     sig[1]=1;smu[1]=1;mul[1]=1;
26     for (int i=2;i<=n;i++){
27         if (!mark[i]){
28             p[++p[0]]=i;
29             mul[i]=-1;
30             smu[i]=1;
31             sig[i]=2;
32         }
33         for (int j=1;j<=p[0]&&p[j]*i<=n;j++){
34             mark[p[j]*i]=1;
35             if (i%p[j]==0){
36                 sig[p[j]*i]=sig[i]/(smu[i]+1)*(smu[i]+2);
37                 smu[p[j]*i]=smu[i]+1;
38                 mul[p[j]*i]=0;
39                 break;
40             }
41             sig[p[j]*i]=sig[i]*2;
42             smu[p[j]*i]=1;
43             mul[p[j]*i]=-mul[i];
44         }
45     }
46     for (int i=1;i<=n;i++) sig[i]+=sig[i-1],smu[i]=smu[i-1]+std::abs((int)mul[i]);
47 }
48
49 ll R(ll x){
50     if (x<=L) return sig[x];
51     ll res=0;
52     for (register ll i=1,j;i<=x;i=j+1){
53         j=(x/(x/i));
54         res+=(j-i+1)*(x/i);
55     }
56     return res;
57 }
58 ll Smu(ll x){
59     if (x<=L) return smu[x];
60     ll res=0;
61     for (register ll i=1;i*i<=x;i++)
62      if (mul[i]) res+=mul[i]*(x/(i*i));
63     return res;
64 }
65 void solve(ll n){
66     int m=sqrt(n);
67     ll ans=0;
68     ll pre=smu[m],tt;
69     for (int i=1;i<=m;i++) if (mul[i]) ans+=R(n/i);
70     for (ll i=m+1,j;i<=n;i=j+1){
71         j=(n/(n/i));
72         tt=Smu(j);
73         ans+=(tt-pre)*(R(n/i));
74         pre=tt;
75     }
76     printf("%lld\n",ans);
77 }
78 int main(){
79     int T=read();
80     ll mx=0;
81     N=1000000000000;
82     for (int i=1;i<=T;i++)
83      a[i]=Read(),mx=std::max(mx,a[i]);
84     if (mx<=10000) L=10000;else L=pow(N,2.0/3.0);
85     Init(L);
86     for (int i=1;i<=T;i++){
87         solve(a[i]);
88     }
89 }
时间: 2024-08-29 05:24:03

SPOJDIVCNT2: Counting Divisors(莫比乌斯反演)的相关文章

【Project Euler】530 GCD of Divisors 莫比乌斯反演

[题目]GCD of Divisors [题意]给定f(n)=Σd|n gcd(d,n/d)的前缀和F(n),n=10^15. [算法]莫比乌斯反演 [题解]参考:任之洲数论函数.pdf 这个范围显然杜教筛也是做不了的,而且考虑直接化简f(n)也遇到了困难,所以考虑将前缀和的Σ一起化简. $$F(n)=\sum_{i=1}^{n}\sum_{d|i}(d,\frac{i}{d})$$ 这一步很常见的是第一重改为枚举倍数,但这样化简后面就推不下去了. 这道题必须最后转成$\sigma_0(n)$才

cf 990G GCD Counting (莫比乌斯反演 并查集)

990G 给你一棵树,问你有多少个点对(x,y)(x\(\leq\)y),使得(x,y)简单路径上的点权值的\(gcd\)为\(i\),对于\(i\in [1,200000]\)输出点对数目. 这题没有做出来,主要还是莫比乌斯反演时间太长不熟悉了.同时统计点对的技巧也自己没有想出来,实在是不应该. 我们设\(h(i)\)是有多少个点对(x,y)(x\(\leq\)y),使得(x,y)简单路径上的点权值的\(gcd\)为\(i\)的倍数的答案.于是有\(h(i)=\sum_{i=1}^{\lflo

HDU-4947-GCD Array(树状数组+莫比乌斯反演)

Problem Description Teacher Mai finds that many problems about arithmetic function can be reduced to the following problem: Maintain an array a with index from 1 to l. There are two kinds of operations: 1. Add v to ax for every x that gcd(x,n)=d. 2.

bzoj 2820 / SPOJ PGCD 莫比乌斯反演

那啥bzoj2818也是一样的,突然想起来好像拿来当周赛的练习题过,用欧拉函数写掉的. 求$(i,j)=prime$对数 \begin{eqnarray*}\sum_{i=1}^{n}\sum_{j=1}^{m}[(i,j)=p]&=&\sum_{p=2}^{min(n,m)}\sum_{i=1}^{\lfloor\frac{n}{p}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{p}\rfloor}[i⊥j]\newline&=&\sum_{p=

Counting Divisors HDU - 6069

Counting Divisors HDU - 6069 题意:给定区间[a,b]和k,求xk有多少因子(x属于[a,b]),求和. 题解:http://blog.csdn.net/zlh_hhhh/article/details/76680641 a.b最大可达到1e12,但是b-a<1e6. 一开始愚蠢的一个一个分解然后去求有多少因子然后求和,范围那么大裸裸的超时啊! 可以枚举素数,对每一个素数,把区间内所有可以分解的进行分解. 最后再求和. 1 #include <bits/stdc++

hdu1695(莫比乌斯反演)

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1695 题意: 对于 a, b, c, d, k . 有 x 属于 [a, b],  y 属于 [c, d], 求 gcd(x, y) = k 的 x, y 的对数 . 其中 a = b = 1 . 注意: (x, y), (y, x) 算一种情况 . 思路: 莫比乌斯反演 可以参考一下: http://blog.csdn.net/lixuepeng_001/article/details/5057

算法学习——莫比乌斯反演(1)

.. 省选GG了,我果然还是太菜了.. 突然想讲莫比乌斯反演了 那就讲吧! 首先我们看一个等式-- (d|n表示d是n的约束) 然后呢,转换一下 于是,我们就发现! 没错!F的系数是有规律的! 规律is here! 公式: 这个有什么卵用呢? 假如说有一道题 F(n)可以很simple的求出来而求f(n)就比较difficult了,该怎么办呢? 然后就可以用上面的式子了 是莫比乌斯函数,十分有趣 定义如下: 若d=1,则=1 若d=p1*p2*p3...*pk,且pi为互异素数,则=(-1)^k

bzoj2301 [HAOI2011]Problem b【莫比乌斯反演 分块】

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=2301 很好的一道题.首先把每个询问转化为4个子询问,最后的结果就是这四个子询问的记过加加减减,类似二维前缀和.那么问题转化为在1 <= x <= lmtx, 1 <= y <= lmty时gcd(x, y) == k的对数,这个问题在转化一下,转化成1 <= x <= lmtx / k,1 <= y <= lmty / k时x与y互质的对数.莫比乌斯反

BZOJ2301: [HAOI2011]Problem b 莫比乌斯反演

分析:对于给出的n个询问,每次求有多少个数对(x,y),满足a≤x≤b,c≤y≤d,且gcd(x,y) = k,gcd(x,y)函数为x和y的最大公约数. 然后对于求这样单个的gcd(x,y)=k的,我们通常采用莫比乌斯反演 但是,时间复杂度是O(n*(n/k))的,当复杂度很坏的时候,当k=1时,退化到O(n^2),超时 然后进行分块优化,时间复杂度是O(n*sqrt(n)) #include<cstdio> #include<cstring> #include<queue