HDU4676 Sum Of Gcd (数论 + 分块)
2016-10-07 14:25
519 查看
∑i=LR∑j=i+1Rgcd(a[i],a[j])=∑i
4000
=LR∑j=i+1R∑d|gcd(a[i],a[j])ϕ(d)=∑dϕ(d)∑i=L,d|a[i]R∑j=i+1,d|a[j]R1
后一项就是[L,R]这段区间内有多少个d的倍数。
cnt[d][x]代表前x项中d的倍数的个数。
原式可化为
∑i=LR∑j=i+1Rgcd(a[i],a[j])=∑dϕ(d)∗(cnt[d][R]−cnt[d][L−1])
如果每一次都是直接求,显然不能满足复杂度,也会爆内存,因为只是一道无修改的查询,自然想到某该的莫队!!!
需要维护的就是该区间内cnd[d]的值。
不妨假设[L,R]到[L−1,R]这个区间。用cnt[d]表示[L,R]之间d的倍数。
发现该区间比上一个区间多了一个∑Ri=Lgcd(a[L−1],a[i])。
由上面的反演可得到:
∑i=LRgcd(a[L−1],a[i])=∑d|a[L−1]ϕ(d)∗∑i=L,d|a[i]R1=∑d|a[L−1]ϕ(d)∗cnt[d]
此时就可以做出答案,当然需要找出a[L−1]的所有约数。如果a[i]<=106那么a[i]最多有100个约数,那么每一次暴力枚举需要o(100),但是这个常数很难达到。
最大的复杂度是o(nn−−√∗100)
但是因为100很难达到,所有可行
///******************
n的所有因数的欧拉函数的和等于n
#include<stdio.h> #include<iostream> #include<math.h> #include<algorithm> #include<string.h> #include <vector> using namespace std; #define LL long long #define INF 0x3f3f3f3f vector<int> G[41000]; int phi[41000]; void init() { for(int i=1;i<21000;i++) for(int j=i;j<21000;j+=i) G[j].push_back(i); phi[1]=1; for(int i=2;i<21000;i++) { if(phi[i]==0) phi[i]=i; else continue; for(int j=i;j<21000;j+=i) { if(phi[j]==0) phi[j]=j; phi[j] = phi[j]/i * (i-1); } } } int n,m,k; int T; struct Node { int l,r,id; } node[41000]; int len; bool cmp(Node a,Node b) { if(a.l/len!=b.l/len) return a.l<b.l; return a.r<b.r; } long long re; long long ans[41000]; int num[41000]; int a[41000]; void add(int pos,int val) { int sz = G[pos].size(); for(int i=0;i<sz;i++) { int v = G[pos][i]; if(val==-1) num[v]--; re = re + (long long) val*phi[v] * num[v]; if(val==1) num[v]++; } } void solve() { int l=0,r=0; re=0; memset(num,0,sizeof(num)); for(int i=0;i<m;i++) { while(l<node[i].l) { add(a[l],-1); l++; } while(l>node[i].l) { l--; add(a[l],1); } while(r<node[i].r) { r++; add(a[r],1); } while(r>node[i].r) { add(a[r],-1); r--; } ans[node[i].id]=re; } } int main() { int cas=1; init(); scanf("%d",&T); while(T--) { scanf("%d",&n); len = sqrt(n); a[0]=0; for(int i=1;i<=n;i++) scanf("%d",&a[i]); scanf("%d",&m); for(int i=0;i<m;i++) { scanf("%d%d",&node[i].l,&node[i].r); node[i].id=i; } sort(node,node+m,cmp); solve(); printf("Case #%d:\n",cas++); for(int i=0;i<m;i++) { printf("%I64d\n",ans[i]); } } return 0; }
。
相关文章推荐
- [数论 反演 && 莫队] hdu4676 . Sum Of Gcd
- HDU4676 Sum Of Gcd
- 【HDU4676】Sum Of Gcd-莫队算法+欧拉函数
- hdu4676 Sum Of Gcd
- [莫比乌斯反演+莫队] HDU4676 Sum Of Gcd
- HDU 4676 Sum Of Gcd(欧拉函数求区间gcd之和+分块算法)
- [数论][莫队][莫比乌斯反演] hdu 4676 Sum Of Gcd
- HDU 4676 Sum Of Gcd【数论,数据结构(分块)】
- HDU 5381 The sum of gcd
- CodeForces 396 B.On Sum of Fractions(数论)
- 莫比乌斯反演 hdu 4676 Sum Of Gcd
- UVA 1210 Sum of Consecutive Prime Numbers(数论)
- HDU 5381 The sum of gcd (技巧,莫队算法)
- HDU 5381 The sum of gcd
- lightOJ 1278 Sum of Consecutive Integers(数论,数学推导)
- Sum Of Gcd HDU - 4676(莫队)
- POJ 1775 Sum of Factorials 数论,基础题
- hdu 5381 The sum of gcd 莫队 + DP
- HDU 5381 The sum of gcd 莫队算法
- hdu5381 The sum of gcd