GCD
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 5303 Accepted Submission(s): 1909
Problem Description
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
题意:给你n个数,m次查询(n,m<=1e5)。每次查询l,r 问区间a[l]~a[r]的GCD为多少,和有多少个区间(l1,r1)gcd和a[l]~a[r]的gcd相等。
思路:很久没单独写过rmq了,趁简单题写一下。首先用RMQ处理出任意区间的GCD,然后对于每一个起点i的值,二分从i开始的区间的gcd可以延伸到多远,然后对于每一个变了的gcd,继续二分直到n。这里由于gcd每次至少/2,而a[i]<=1e9,所以不会超过30次。然后答案用map保存就可以了。注意可能会爆int,所以用long long。这样预处理的时间复杂度是O(nlogn),查询是O(logn)。有不理解或者疑惑的地方欢迎评论。
代码:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=1e5+10;
int f[maxn][20],a[maxn];
int n,m;
int gcd(int a,int b)
{
return b?gcd(b,a%b):a;
}
void rmq()
{
for(int i=1;i<=n;i++)f[i][0]=a[i];
for(int i=1;i<20;i++)
for(int j=1;j<=n;j++)
if(j+(1<<i)-1<=n) f[j][i]=gcd(f[j][i-1],f[j+(1<<i-1)][i-1]);
}
int query(int l,int r)
{
int k=(int)log2((double)(r-l+1));
return gcd(f[l][k],f[r-(1<<k)+1][k]);
}
map<int,long long>mp;
void go()
{
mp.clear();
for(int i=1;i<=n;i++)
{
int g=f[i][0],j=i;
while(j<=n)
{
int l=j,r=n;
while(l<r)
{
int mid=(l+r+1)>>1;
if(query(i,mid)==g) l=mid;
else r=mid-1;
}
mp[g]+=l-j+1;
j=l+1;
g=query(i,j);
}
}
}
int main()
{
int T,cas=1;
scanf("%d",&T);
while(T--)
{
printf("Case #%d:\n",cas++);
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
rmq();
go();
scanf("%d",&m);
while(m--)
{
int x,y;
scanf("%d%d",&x,&y);
int t=query(x,y);
printf("%d %lld\n",t,mp[t]);
}
}
return 0;
}