题目链接
Give you a sequence of N(N≤100,000) integers : a1,…,an(0<ai≤1000,000,000). There are Q(Q≤100,000) queries. For each query l,r you have to calculate gcd(al,al+1,…,ar) and count the number of pairs(l′,r′)(1≤l<r≤N)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<ai≤1000,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
2016 Multi-University Training Contest 1
思路:区间gcd我们可以用线段树求,可是相同的对数怎么求呢?我们知道一个长度为n的子区间内的gcd个数肯定是不超过log个的,因为枚举是可能的,当枚举到a【i】时,遍历一下之前在【1,a【i-1】】求的gcd的种类和个数进行计数,查询时就可以O(1)。比如说前面1到a【i-1】中已经有一个gcd是x,那么现在gcd(x,a【i】)等于y,那么cnt【y】就等于本身存在的个数+gcd(x)的个数,存gcd的话用map映射一下。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+1;
ll a[maxn];
ll gcd (ll a,ll b)
{
return b==0?a:gcd(b,a%b);
}
struct node{
int l,r;
ll num;
}tree[maxn<<2];
map<ll,ll>p1,p2,cnt;
void build(int l,int r,int x)
{
tree[x].l=l,tree[x].r=r;
if(l==r){
tree[x].num=a[l];return ;
}
int mid=(l+r)>>1;
build(l,mid,x<<1);
build(mid+1,r,x<<1|1);
tree[x].num=gcd(tree[x<<1].num,tree[x<<1|1].num);
}
ll query(int x,int l,int r)
{
if(l==tree[x].l&&tree[x].r==r) return tree[x].num;
int mid=(tree[x].l+tree[x].r)>>1;
if(r<=mid) return query(x<<1,l,r);
else if(l>mid) return query(x<<1|1,l,r);
else return gcd(query(x<<1,l,mid),query(x<<1|1,mid+1,r));
}
int main()
{
int T,n,m,l,r;
scanf("%d",&T);
for(int j=1;j<=T;++j)
{
printf("Case #%d:\n",j);
scanf("%d",&n);
p1.clear(),p2.clear(),cnt.clear();
for(int i=1;i<=n;++i)
{
scanf("%lld",&a[i]);
cnt[a[i]]++;
p2[a[i]]++;
for(auto it=p1.begin();it!=p1.end();it++)
{
ll t=gcd(a[i],it->first);
cnt[t]+=it->second;
p2[t]+=it->second;
}
p1.clear();
for(auto it=p2.begin();it!=p2.end();it++) p1[it->first]=it->second;
p2.clear();
}
build(1,n,1);
scanf("%d",&m);
while(m--)
{
scanf("%d%d",&l,&r);
ll ans=query(1,l,r);
printf("%lld %lld\n",ans,cnt[ans]);
}
}
}