HDU5381-The sum of gcd

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=lrj=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
1T3
1n,Q104
1ai109
1l<rn
 

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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值