链接: HDU-5726-GCD
题意:
给你n个数(n<=1e5)然后m个询问(m<=1e5),每个询问一个区间,问你这个区间的GCD是多少,并且输出从1到n有多少个区间的GCD和这个区间的相同。
思路:
首先我们需要知道区间gcd的性质:
假设我们固定右端点,区间向左延伸,那么gcd个数一定是呈现非递增性质的,即要么不变要么减小,并且减小的话一定减少一半,因为实际上一段区间内,不同的gcd的个数,不会超过log个。
第一部分可以用线段树维护区间的GCD,第二部分,我们可以固定一个右端点,找出每一个gcd值变化的左端点,这个区间的长度就是区间gcd出现的次数。类似于递推的思路,具体看代码。
代码:
#include <iostream>
#include <cstdio>
#include <queue>
#include <math.h>
#include <map>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn = 1e6 + 7;
typedef long long ll;
const int mod=1e9+7;
int T;
int n,j;
int a[maxn];
int sum[maxn];
int v[maxn],l[maxn];
map<int ,ll >mp;
void build(int l,int r , int rt){
if(l == r){
sum[rt] = a[l];
return ;
}
int mid = (l + r) / 2;
build(l , mid , rt << 1);
build(mid + 1 , r , rt << 1 | 1);
sum[rt] = __gcd(sum[rt << 1] , sum[rt << 1 | 1]);
}
int query(int L,int R,int l, int r , int rt){
if(L <= l && R >= r){
return sum[rt];
}
int ans = 0;
int mid = (l + r) / 2;
if(L <= mid) ans