The sum of gcd
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 1367 Accepted Submission(s): 596
Problem Description
You have an array
A
,the length of
A
is
n
Let f(l,r)=∑ri=l∑rj=igcd(ai,ai+1....aj)
Let f(l,r)=∑ri=l∑rj=igcd(ai,ai+1....aj)
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 integers n
Second line has n integers Ai
Third line has one integers Q ,the number of questions
Next there are Q lines,each line has two integers l , r
1≤T≤3
1≤n,Q≤104
1≤ai≤109
1≤l<r≤n
First line has one integers n
Second line has n integers Ai
Third line has one integers Q ,the number of questions
Next there are Q lines,each line has two integers l , r
1≤T≤3
1≤n,Q≤104
1≤ai≤109
1≤l<r≤n
Output
For each question,you need to print
f(l,r)
Sample Input
2 5 1 2 3 4 5 3 1 3 2 3 1 4 4 4 2 6 9 3 1 3 2 4 2 3
Sample Output
9 6 16 18 23 10
Author
SXYZ
Source
Recommend
wange2014
题意:给你一个序列有n个数,有m次询问,每次询问一个区间所有子区间gcd的和
解题思路:线段树,因为对一个数来所,它的gcd是不会超过log2(n)个的,所以可以每个节点记录从最左端向右延伸和从最右端向左延伸所有gcd的种类和个数,同时记录下这个区间的gcd和这个区间的答案
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <cmath>
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <vector>
#include <bitset>
#include <functional>
using namespace std;
#define LL long long
const int INF = 0x3f3f3f3f;
int t, n, m;
int gcd(int x, int y)
{
return x ? gcd(y%x, x) : y;
}
struct node
{
int x;
LL sum;
vector<pair<int, LL> > l, r;
}a[10009 << 2], ans;
void Merge(node &a, node b, node c)
{
a.l.clear(); a.r.clear();
a.x = gcd(b.x, c.x);
a.sum = b.sum + c.sum;
for (int i = 0; i < b.l.size(); i++) a.l.push_back(b.l[i]);
for (int i = 0; i < c.l.size(); i++)
{
int k = gcd(b.x, c.l[i].first);
if (k == a.l[a.l.size() - 1].first) a.l[a.l.size() - 1].second += c.l[i].second;
else a.l.push_back(make_pair(k, c.l[i].second));
}
for (int i = 0; i < c.r.size(); i++) a.r.push_back(c.r[i]);
for (int i = 0; i < b.r.size(); i++)
{
int k = gcd(c.x, b.r[i].first);
if (k == a.r[a.r.size() - 1].first) a.r[a.r.size() - 1].second += b.r[i].second;
else a.r.push_back(make_pair(k, b.r[i].second));
}
for (int i = 0; i < b.r.size(); i++)
for (int j = 0; j < c.l.size(); j++)
{
int k = gcd(b.r[i].first, c.l[j].first);
a.sum += b.r[i].second * c.l[j].second * k;
}
}
void build(int k, int l, int r)
{
a[k].l.clear(); a[k].r.clear();
if (l == r)
{
scanf("%d", &a[k].x);
a[k].sum = a[k].x;
a[k].l.push_back(make_pair(a[k].x, 1)); a[k].r.push_back(make_pair(a[k].x, 1));
return;
}
int mid = l + r >> 1;
build(k << 1, l, mid); build(k << 1 | 1, mid + 1, r);
Merge(a[k], a[k << 1], a[k << 1 | 1]);
}
void query(int k, int l, int r, int ll, int rr)
{
if (ll <= l&&r <= rr)
{
if (ans.x) Merge(ans, ans, a[k]);
else ans = a[k];
return;
}
int mid = l + r >> 1;
if (ll <= mid) query(k << 1, l, mid, ll, rr);
if (rr > mid) query(k << 1 | 1, mid + 1, r, ll, rr);
}
int main()
{
int t;
scanf("%d", &t);
while (t--)
{
scanf("%d", &n);
build(1, 1, n);
scanf("%d", &m);
while (m--)
{
int l, r;
scanf("%d%d", &l, &r);
ans.x = 0;
query(1, 1, n, l, r);
printf("%lld\n", ans.sum);
}
}
return 0;
}