HDU 5381 The sum of gcd
来源:互联网 发布:c语言面向对象编程的书 编辑:程序博客网 时间:2024/06/06 05:16
The sum of gcd
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Problem Description
You have an array A ,the length of A is n
Letf(l,r)=∑ri=l∑rj=igcd(ai,ai+1....aj)
Let
Input
There are multiple test cases. The first line of input contains an integer T, indicating the number of test cases. For each test case:
First line has one integersn
Second line hasn integers Ai
Third line has one integersQ ,the number of questions
Next there are Q lines,each line has two integersl ,r
1≤T≤3
1≤n,Q≤104
1≤ai≤109
1≤l<r≤n
First line has one integers
Second line has
Third line has one integers
Next there are Q lines,each line has two integers
Output
For each question,you need to print f(l,r)
Sample Input
251 2 3 4 531 32 31 444 2 6 931 32 42 3
Sample Output
9616182310
上一篇是用gcd性质处理出每个端点的gcd变化位置,这一篇是用了RMQ加二分预处理出所有的gcd变化位置,然后再用莫队算法求解。
类似的RMQ二分预处理还有HDU 5726这一题。
#pragma comment(linker, "/STACK:1024000000,1024000000")#include <set>#include <map>#include <stack>#include <cmath>#include <queue>#include <cstdio>#include <bitset>#include <string>#include <vector>#include <iomanip>#include <cstring>#include <iostream>#include <algorithm>#include <functional>#define maxn 50500using namespace std;typedef long long ll;const int N = 10000 + 5;int n, m;int block;int a[N];ll ans[N];int ggcd[23][maxn*2];struct Node{ int L, R; int id; bool operator<(const Node&rhs)const { if (L / block == rhs.L / block) { return R < rhs.R; } return L / block < rhs.L / block; }} q[N];int gcd(int a, int b){ return (b == 0) ? a : gcd(b, a % b);}void ST(int num){ for (int i = 1; i <= num; i++) { ggcd[0][i] = a[i]; } for (int i = 1; i <= log2(num); i++) for (int j = 1; j <= num; j++) if (j + (1 << i) - 1 <= num) { int a = ggcd[i - 1][j], b = ggcd[i - 1][j + (1 << i >> 1)]; ggcd[i][j]=gcd(a,b); }}int RMQ(int x, int y){ int k = (int) log2(y - x + 1.0); int a = ggcd[k][x], b = ggcd[k][y - (1 << k) + 1]; return gcd(a,b);}struct He{ int idx; ll g;};vector<He>vl[N], vr[N];void preDeal(){ ST(n); for(int i=1;i<=n;i++) { int g=ggcd[0][i],j=i; while(j<=n) { int left = j,right=n,mid; while(left <= right) { mid =(left + right)/2; if(RMQ(i,mid)>=g) { left =mid +1; } else { right =mid -1; } } mid = (left+right)/2; vr[i].push_back(He{mid,g}); j=mid+1; g=RMQ(i,j); } } for(int i=n;i>=1;i--) { int g=ggcd[0][i],j=i; while(j>=1) { int left = 1,right=j,mid; while(left <= right) { mid =(left + right)/2; if(RMQ(mid,i)<g) { left =mid +1; } else { right =mid -1; } } mid = (left+right)/2; vl[i].push_back(He{mid+1,g}); j=mid; g=RMQ(j,i); } }}ll calc(int type, int L, int R) //计算区间[L,R]的结果{ ll res = 0; if (!type) { int tr = R; //当前的右端点 for (auto&it : vl[R]) if (it.idx >= L) //如果当前区间的左端点>=L,则当前区间为[it.idx,tr] { //这里其实用到了GCD值的传递性: //如果L<L1<R,gcd([L,R])=g1,gcd([L1,R])=g2(g2≥g1),那么必有gcd([L,L1-1])=g1 res += (tr - it.idx + 1) * it.g; tr = it.idx - 1; //更新右端点 } else //如果当前区间的左端点<L,则应该被算入的区间为[L,tr],由于它是最后一个区间了,因此break { res += (tr - L + 1) * it.g; break; } } else //原理同上 { int tl = L; for (auto&it : vr[L]) if (it.idx <= R) { res += (it.idx - tl + 1) * it.g; tl = it.idx + 1; } else { res += (R - tl + 1) * it.g; break; } } return res;}void solve(){ for (int i = 1; i <= n; i++) { vl[i].clear(), vr[i].clear(); } block = sqrt(n); //块数 sort(q, q + m); preDeal(); int L = 1, R = 0;//从(1, 0)点开始转移,此时res = 0 ll res = 0; for (int i = 0; i < m; i++) { while (R < q[i].R) { R++;//向右右端点,然后计算[L,R]区间的结果,累加给res res += calc(0, L, R); } while (R > q[i].R) //向左移动右端点 { res -= calc(0, L, R); R--; } while (L > q[i].L) { L--; res += calc(1, L, R); } while (L < q[i].L) { res -= calc(1, L, R); L++; } ans[q[i].id] = res; //转移完毕。注意,res,L,R都不要清零 } for (int i = 0; i < m; i++) { printf("%I64d\n", ans[i]); }}int main(){ int T; scanf("%d", &T); while (T--) { scanf("%d", &n); for (int i = 1; i <= n; i++) { scanf("%d", &a[i]); } scanf("%d", &m); for (int i = 0; i < m; i++) { scanf("%d%d", &q[i].L, &q[i].R); q[i].id = i; } solve(); } return 0;}
0 0
- HDU 5381 The sum of gcd
- hdu 5381 The sum of gcd
- hdu 5381 The sum of gcd
- HDU 5381The sum of gcd
- HDU 5381 The sum of gcd
- HDU 5381 The sum of gcd
- HDU 5381 The sum of gcd
- hdu 5381 The sum of gcd(线段树+gcd)
- hdu 5381 The sum of gcd 莫队 + DP
- HDU 5381 The sum of gcd 莫队暴力
- HDU 5381 The sum of gcd 离线处理+线段树
- hdu 5381 The sum of gcd(线段树)
- HDU 5381The sum of gcd 莫队算法
- hdu 5381 The sum of gcd 莫队算法+区间gcd
- HDU 5381(The sum of gcd-莫队算法解决区间段gcd的和)
- 莫队算法,gcd(The sum of gcd,HDU 5381)
- Sum Of Gcd HDU
- hdu 5381 The sum of gcd 2015多校联合训练赛#8莫队算法
- Ajax基本案例详解之load的实现
- JAVA面向对象的三大特点
- opencv 函数(一)
- Mybatis介绍之参数传递
- FU-A分包方式,以及从RTP包里面得到H.264数据和AAC数据的方法
- HDU 5381 The sum of gcd
- android activity FLAG_ACTIVITY_CLEAR_TASK 跳转出现短暂的白屏或黑屏现象
- Python学习之字符串(一)
- 24点游戏
- CentOS7 挂载NTFS分区
- activiti学习笔记9--Mapped Diagnostic Contexts--20170412
- Android知晓当前活动
- 算法——cracking the coding interview150解答
- 题目1027:欧拉回路