HDU 5726 GCD (线段树维护区间gcd)

本文介绍了一种解决区间GCD查询问题的有效方法,通过预处理和分治思想,实现快速查询任意区间内的最大公约数及其出现次数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

GCD

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 2445    Accepted Submission(s): 855

Problem Description
Give you a sequence of N(N100,000) integers : a1,...,an(0<ai1000,000,000) . There are Q(Q100,000) queries. For each query l,r you have to calculate gcd(al,,al+1,...,ar) and count the number of pairs (l,r)(1l<rN) such that gcd(al,al+1,...,ar) equal gcd(al,al+1,...,ar) .
Input
The first line of input contains a number T , which stands for the number of test cases you need to solve.

The first line of each case contains a number N , denoting the number of integers.

The second line contains N integers, a1,...,an(0<ai1000,000,000) .

The third line contains a number Q , denoting the number of queries.

For the next Q lines, i-th line contains two number , stand for the li,ri , stand for the i-th queries.
Output
For each case, you need to output “Case #:t” at the beginning.(with quotes, t means the number of the test case, begin from 1).

For each query, you need to output the two numbers in a line. The first number stands for gcd(al,al+1,...,ar) and the second number stands for the number of pairs (l,r) such that gcd(al,al+1,...,ar) equal gcd(al,al+1,...,ar) .
Sample Input
  
1 5 1 2 4 6 7 4 1 5 2 4 3 4 4 4
Sample Output
  
Case #1: 1 8 2 4 2 4 6 1
Author
HIT
Source
Recommend
wange2014   |   We have carefully selected several similar problems for you:  5775 5774 5773 5772 5771 

题解:给你n个数,然后有 m个询问,每个询问一个区间,问你这个区间的GCD是多少,并且问你从1到n有多少个区间的GCD和这个区间的GCD是相同的。

AC代码:
#include<bits/stdc++.h>
using namespace std;  
typedef long long ll; 
#define lson l,m,rt<<1  
#define rson m+1,r,rt<<1|1  
map<int,ll>mp;  
const int N=1e5+7;  
int n,i,j,a[N],l[N],v[N],tr[N<<2];  
using namespace std;
void init(){  
    mp.clear();  
    scanf("%d",&n);  
    for(int i=1 ; i<=n ; i++)
		scanf("%d",a+i);  
    for(int i=1; i <= n; i++)
		for(v[i]=a[i],j=l[i]=i; j ; j=l[j]-1)
		{	  
        	v[j]=__gcd(v[j],a[i]);  
        	while(l[j] > 1 && __gcd(a[i],v[l[j]-1])==__gcd(a[i],v[j]))
				l[j] = l[l[j] - 1];  
        	mp[v[j]] += j - l[j] + 1;  
    	}  
}  
void build(int l=1,int r=n,int rt=1)
{  
    if(l==r){
		tr[rt]=a[l];
		return;
	}  
    int m=(l+r)>>1;  
    build(lson);
	build(rson); 
    tr[rt]=__gcd( tr[rt<<1] , tr[rt<<1|1]);  
}  

int query(int L,int R,int l=1,int r=n,int rt=1)
{  
	
    if(L<=l&&r<=R)	return tr[rt];  
    int m=(l+r)>>1;  
    if(R<=m)	return query(L,R,lson);  
    if(L>m) 	return query(L,R,rson);  
    return __gcd(query(L,R,lson) , query(L,R,rson));  
}  
int main()
{
	int t;
	int x,y,k;
	int cas= 1;
	scanf("%d",&t);
	while(t--)
	{
		init();
		build();
		scanf("%d",&k);
		printf("Case #%d:\n",cas++);
		while(k--)
		{
			scanf("%d%d",&x,&y);
			int ans = query(x,y);
			printf("%d %lld\n",ans,mp[ans]);
		}
	}
	return 0;
}



 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值