2016多校第一场1004 hdu 5726 GCD

本文介绍了一种解决HDU 5726题目中关于区间GCD查询的有效方法。通过记录类似前缀和的信息,并利用特定算法进行区间合并,解决了寻找特定区间GCD及与其相等的区间数量的问题。

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

####题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=5726
####题目大意:
对于一个序列,询问某个区间的gcd,和区间gcd与之相等的区间个数。
####解题思路:
之前做过区间内两两元素之间gcd和的题目,以为要用高级的数据结构,一直没有思路,看了标程,没有什么特殊的算法,就是记录类似前缀和的东西,还是对这种思路用的不够熟练。
标程的做法是:对于每个数字,记录从开始到当前数字的区间的子区间中以当前数字为结尾区间的gcd,相同gcd区间合并。具体过程看代码。这有一个知识点,一个百万级别的数大概有二百多个因子,所以109的因子也不会太多(没有证明,强行解释)。这样记录不会超内存。算法的复杂度应该在107左右 O(tn公因子个数)。
####代码:

/* ********************************
Author			: danmu
Created Time	: 2016年07月20日 星期三 04时08分39秒
File Name		: d.cpp
******************************** */

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <string>
#include <vector>
#include <cstdio>
#include <stack>
#include <queue>
#include <cmath>
#include <list>
#include <map>
#include <set>

#define rep(i,x,y) for(int i=x;i<=y;++i)
#define _rep(i,x,y) for(int i=x;i>=y;--i)
#define CL(S,x) memset(S,x,sizeof(S))
#define CP (S1,S2) memcpy(S1,S2,sizeof(S2))
#define ALL(x,S) for(x=S.begin();x!=S.end();++x)
#define ULL unsigned long long
#define PI 3.1415926535
#define INF 0x3f3f3f3f
#define LL long long

const int maxn = 1e5+10;
const int mod = 1e9 + 7;
const double eps = 1e-8;

using namespace std;
int a[maxn];
vector<pair<int,int> > record[maxn];
map<int,LL> ans;
int gcd(int a,int b){
	return b?gcd(b,a%b):a;
}
int main(){
	//freopen("in.txt", "r", stdin);
	//freopen("out.txt", "w", stdout);
	int t;
	scanf("%d",&t);
	for(int ca=1;ca<=t;++ca){
		int n,q;
		ans.clear();
		scanf("%d",&n);
		for(int i=0;i<=n;++i)
			record[i].clear();
		for(int i=1;i<=n;++i){
			int last=0;
			scanf("%d",a+i);
			for(int j=0;j<record[i-1].size();++j){
				int tmp=gcd(a[i],record[i-1][j].first);
				if(tmp==last) continue;
				last=tmp;
				record[i].push_back(make_pair(tmp,record[i-1][j].second));
			}
			if(last!=a[i])
				record[i].push_back(make_pair(a[i],i));
			for(int j=0;j<record[i].size();++j)
				ans[record[i][j].first]+=(j==record[i].size()-1?i+1:record[i][j+1].second)-record[i][j].second;
		}
		printf("Case #%d:\n",ca);
		scanf("%d",&q);
		for(int i=0;i<q;++i){
			int u,v,j;
			scanf("%d%d",&u,&v);
			for(j=0;j<record[v].size();++j)
				if(record[v][j].second>u)
					break;
			printf("%d %lld\n",record[v][j-1].first,ans[record[v][j-1].first]);
		}
	}	
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值