GCD
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
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.
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) .
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
直接RMQ预处理+二分查找T了。因为查询次数太多,其实gcd种类数目不多,所以可以先预处理开个map记录gcd为某个值的数目。
先for循环遍历区间起点,然后二分查找每次区间gcd变化时的终点,存到map中。
/*
RMQ-ST算法 + 二分预处理
查询次数太多,不能直接二分查询
因为GCD其实最多只有nlog2(n)种 所以可以先预处理在map中
*/
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <set>
#include <map>
#include <stack>
#include <cmath>
#include <queue>
#include <cstdio>
#include <bitset>
#include <string>
#include <vector>
#include <iomanip>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <functional>
#define inf 0x7fffffff
#define maxn 100010
using namespace std;
int gcd[23][maxn*2];
int a[maxn];
long long ans;
int n, q;
void ST(int num)
{
for (int i = 1; i <= num; i++)
{
gcd[0][i] = a[i];
}
for (int i = 1; i <= log2(num); i++)
for (int j = 1; j <= num; j++)
if (j + (1 << i) - 1 <= num)
{
int a = gcd[i - 1][j], b = gcd[i - 1][j + (1 << i >> 1)];
gcd[i][j]=__gcd(a,b);
}
}
int RMQ(int x, int y)
{
int k = (int) log2(y - x + 1.0);
int a = gcd[k][x], b = gcd[k][y - (1 << k) + 1];
return __gcd(a,b);
}
int main()
{
int T;
scanf("%d", &T);
for(int tt=1;tt<=T;tt++)
{
scanf("%d", &n);
for (int i = 1; i <= n; i++)
{
scanf("%d", &a[i]);
}
ST(n);
scanf("%d",&q);
printf("Case #%d:\n",tt);
map<int,long long> mp;
for(int i=1;i<=n;i++)
{
int g=gcd[0][i],j=i;
while(j<=n)
{
int left = j, right = n, mid;
while (left <= right)
{
mid = (left + right) / 2;
if (RMQ(i, mid) >= g)
{
left = mid + 1;
}
else
{
right = mid - 1;
}
}
mid=(left+right)/2;
mp[g]+=(mid-j+1);
j=mid+1;
g=RMQ(i,j);
}
}
while(q--)
{
int a,b;
scanf("%d %d",&a,&b);
int ans=RMQ(a,b);
printf("%d %I64d\n",ans,mp[ans]);
}
}
return 0;
}