hdu5726

题意:给定一个序列,多次询问[L,R],输出这段区间的最大公约数,以及为此公约数的区间个数。

思路,用RMQ处理,然后对每个左端点i,二分搜索最远的右端点R,使i到这个端点区间内最大公约数相同,用MAP记录此段区间个数,一直处理到R=n;

二分搜索不知为什么用while(high-low>1)这种总是WA,自己写的样例却都对。。保险起见,以后还是用while(low<=high)这种吧

#include<cstdio>
#include<algorithm>
#include<string>
#include<cstring>
#include<sstream>
#include<iostream>
#include<cmath>
#include<queue>
#include<map>
using namespace std;

int a[100000+5];
int dp[100000+5][30];
int n;
map<int,long long> MAP_cnt;

int gcd(int x,int y){
	if(y==0){
		return x;
	}else
	    return gcd(y,x%y);
}

void init(){
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
		dp[i][0]=a[i];
	}
	for(int j=1;(1<<j)<=n;j++){
		for(int i=1;i+(1<<j)-1<=n;i++){
			dp[i][j]=gcd(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
		}
	}
}

int RMQ(int L,int R){
	int x=(double)log(R-L+1)/log(2);
	return(gcd(dp[L][x],dp[R-(1<<x)+1][x]));
}

int main(){
//	freopen("input.txt","r",stdin);
	int T;
	cin>>T;
	for(int CASE=1;CASE<=T;CASE++){
		MAP_cnt.clear();
		scanf("%d",&n);
		init();
		for(int i=1;i<=n;i++){
			int L=i,R=i;
			while(R<=n){
				int low=L,high=n;
				int t=RMQ(i,L);
				while(low<=high){
					int mid=(high+low)/2;
					if(RMQ(i,mid)==t){
						low=mid+1;
					}else{
						high=mid-1;
					}	
				}
				R=low;
				MAP_cnt[t]+=(long long)R-L;
				L=R;
			}
		}
		printf("Case #%d:\n",CASE);
		int m,x,y;
		scanf("%d",&m);
		while(m--){
			scanf("%d%d",&x,&y);
			int GCD=RMQ(x,y);
			printf("%d %lld\n",GCD,MAP_cnt[GCD]);
		}	
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值