莫队算法 区间Gcd Hdu 5381
来源:互联网 发布:淘宝联盟和淘客联盟 编辑:程序博客网 时间:2024/05/20 19:18
The sum of gcd
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 1323 Accepted Submission(s): 581
Let
First line has one integers
Second line has
Third line has one integers
Next there are Q lines,each line has two integers
251 2 3 4 531 32 31 444 2 6 931 32 42 3
9616182310
所谓 f(l,r) 就比如
f(1,3) =gcd(a1,a1) + gcd(a1,a2) + gcd(a1,a2,a3)
+ gcd(a2,a2) + gcd(a2,a3)
+ gcd(a3,a3)
就相当于 (a1,a2,a3) 然后枚举每个数,向后尺取gcd
思路:依然是按照莫队的 sqrt(n)分块,排序询问,然后移动指针找答案
1.先打印好前缀的 lgcd 和 后缀 rgcd ,我使用动态数组存的,节省很多空间
但是里面有一个巧妙的地方是,不把所有的前缀都存进去,只存gcd值不一样的,且记录下第一个不一样的gcd的下标。这样的话,你取了一个gcd之后,下一个gcd值的个数可以通过前一个的下标和当前下标相减求得,也是节省了时间的。 前缀后缀都这么记录
2.开始移动指针,当右指针右移的时候,表示向右加数,对于加的那个数的每个gcd贡献,去与左极限对比找出贡献个数,然后加上。,右指针左移则是减贡献。移动好右指针后移动左指针,操作相同,不过左指针是与右极限对比找该gcd值的贡献个数。
做个模拟比较易懂
5 [1, 2 ,3 ,4 ,5] 询问 [ 1,3 ]
左指针 l = 1, 右指针 r = 0
1.右指针向右 移1, rgcd[1] 里只有 (1,1) (ps:表示贡献gcd值为1,下标为1) Ans += 1 Ans = 1
2.右指针向右 移1, rgcd[2] 里右 (2,2) (1,1) (ps:因为 gcd(1,2) = 1,gcd为1的下标开始为1)
(2,2) Ans += 2 , (1,1) Ans += 1 * (2 - 1) Ans = 4;
3.右指针向右移1 , rgcd[3] 里有 (3,3) (1,1)
(3,3) Ans += 3
(1,1) Ans += 1 * (3 - 1) (ps:开始下标为1,现在为3,那么中间就是有两个贡献为1的,分别是 (1,3) 和(2,3) )Ans = 9
#include<cstdio>#include<iostream>#include<cstring>#include<algorithm>#include<cmath>#include<vector>using namespace std;#define maxn 10004#define mem(a,x) memset(a,x,sizeof(a))#define ll long long struct node{ int l,r,id;}q[maxn];typedef pair<int,int>P;vector<P>lgcd[maxn],rgcd[maxn];int T,n,m,l,r;int pos[maxn],a[maxn];ll ans[maxn];ll Ans = 0;bool cmp(node a,node b){ if(pos[a.l] != pos[b.l]) return pos[a.l] < pos[b.l]; if(pos[a.r] != pos[b.r]) return pos[a.r] < pos[b.r]; return a.l < b.l;}void addl(int x){ int last = l; ll tmp = 0; for(int i = 0;i < lgcd[l].size();i++){ // 找到它的gcd贡献 int g = lgcd[l][i].first,p = lgcd[l][i].second;//获得这个gcd值的 开始下标 if(p <= r){ tmp += 1ll * (p - last + 1) * g; // (p - last + 1)表示有多少个连续相同的gcd值,一起算完 last = p + 1; }else{ tmp += 1ll * (r - last + 1) * g; break; } } Ans += 1ll * x * tmp; // x = -1 表示减 1 则为加 }void addr(int x){ int last = r; ll tmp = 0; for(int i = 0;i < rgcd[r].size();i++){ int g = rgcd[r][i].first,p = rgcd[r][i].second; //获得这个gcd值的 结束下标 if(p >= l){ tmp += 1ll * (last - p + 1) * g;// (last - p + 1)表示有多少个连续相同的gcd值,一起算完 last = p - 1; }else{ tmp += 1ll * (last - l + 1) * g; break; } } Ans += 1ll * x * tmp;}void init(){ for(int i = 1;i <= n;i++){// rgcd[x] 存以x为结尾的连续gcd int x = a[i],y = i; for(int j = 0;j < rgcd[i - 1].size();j++){ int g = __gcd(rgcd[i - 1][j].first,a[i]); if(g != x){ rgcd[i].push_back(P(x,y)); x = g; } y = rgcd[i - 1][j].second; } rgcd[i].push_back(P(x,y)); } for(int i = n;i >= 1;i--){// lgcd[x] 存以x开头的连续gcd int x = a[i],y = i; for(int j = 0;j < lgcd[i + 1].size();j++){ int g = __gcd(lgcd[i + 1][j].first,a[i]); if(g != x){ lgcd[i].push_back(P(x,y)); // 不会全部存进去,连续相同的会跳过 x = g; } y = lgcd[i + 1][j].second; } lgcd[i].push_back(P(x,y)); } }int main(){ scanf("%d",&T); while(T--){ scanf("%d",&n); int block = sqrt(n); for(int i = 1;i <= n;i++){ scanf("%d",&a[i]); pos[i] = i / block; rgcd[i].clear(); lgcd[i].clear(); } rgcd[0].clear(); lgcd[0].clear(); init();// 打好前缀和后缀 scanf("%d",&m); for(int i = 1;i <= m;i++){ scanf("%d %d",&q[i].l,&q[i].r); q[i].id = i; } sort(q + 1,q + 1 + m,cmp);//分块排序 Ans = 0; l = 1,r = 0; for(int i = 1;i <= m;i++){ //移动找答案 while(r < q[i].r){ r++; addr(1); } while(r > q[i].r){ addr(-1); r--; } while(l < q[i].l){ addl(-1); l++; } while(l > q[i].l){ l--; addl(1); } ans[q[i].id] = Ans; } for(int i = 1;i <= m;i++){ printf("%lld\n",ans[i]); } } return 0;}
- 莫队算法 区间Gcd Hdu 5381
- hdu 5381 The sum of gcd 莫队算法+区间gcd
- HDU 5381(The sum of gcd-莫队算法解决区间段gcd的和)
- HDU 5381 The sum of gcd 询问区间内所有子区间的GCD和 [莫队算法]
- HDU5381【莫队算法+区间GCD特性】
- hdu 5381 莫队算法/gcd
- HDU 5381The sum of gcd 莫队算法
- hdu 5726(区间gcd)
- 莫队算法,gcd(The sum of gcd,HDU 5381)
- HDU 4676 Sum Of Gcd(欧拉函数求区间gcd之和+分块算法)
- hdu 5726 GCD (区间gcd-RMQ)
- [反演 莫队算法] HDU 4676 Sum Of Gcd
- 【HDU5381_多校第八场B】【莫队算法】区间GCD之和_分段预处理
- hdu 5381 The sum of gcd 2015多校联合训练赛#8莫队算法
- HDU 5381 The sum of gcd(数论+莫队算法)
- HDU 5381 The sum of gcd 询问区间内所有子区间的GCD和 [暴力法]
- Hdu-5869 Different GCD Subarray Query(区间不同值离线算法)
- hdu 5786 Interval 区间gcd求和
- mysql获取group by的总记录行数方法
- 三星C8将于9月7日发布,售价仅1999?
- 提取xml格式新闻内容
- 牛客网C++知识点整理(持续更新)
- 90个PHP常用接口数据过滤的方法
- 莫队算法 区间Gcd Hdu 5381
- ajax学习
- com.netflix.zuul.exception.zuulexception timeout
- activiti部署、执行,完成简单示例
- TensorFlow下载与安装(Ubuntu)
- RobotFramework之关键字
- LeetCode 39. Combination Sum
- java对象的多态性
- 递归遍历无限级分类