GCD
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 1271 Accepted Submission(s): 391
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
Author
HIT
Source
Recommend
题目大意:
给出一个长为n的数列a,0 < ai <= 1e9
Q次查询,每次询问区间[L,R]的GCD,还有整个数列中同样GCD的区间个数
问题一,用RMQ即可搞定,因为GCD跟Min是一种极性,都是不增函数
问题二,暴力统计一下即可,从a[0]到a[n],一个映射存放全局的各GCD区间个数,一个映射存放遍历到当前位置,连续的各GCD区间个数,这样用当前的a[i]与连续到当前未知的各GCD求gcd,然后累加到全局的映射中,同时建立新的更新的映射,同时把a[i]加入新映射,表示a[i]自己这个区间
代码如下:
#include <iostream>
#include <cmath>
#include <vector>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <queue>
#include <stack>
#include <list>
#include <algorithm>
#include <map>
#include <set>
#define LL long long
#define Pr pair<int,int>
#define fread(ch) freopen(ch,"r",stdin)
#define fwrite(ch) freopen(ch,"w",stdout)
using namespace std;
const int INF = 0x3f3f3f3f;
const int msz = 10000;
const int mod = 1e9+7;
const double eps = 1e-8;
map <int,LL> tmp;
map <int,LL> a,b;
map <int,LL>::iterator iter;
int rmq[111111][22];
int cs[111111];
int Search(int l,int r)
{
int cnt = (r-l+1);
int k = cs[cnt];
//printf("%d %d %d %d %d\n",l,r-cnt+1,rmq[l][k],rmq[r-cnt+1][k],k);
return __gcd(rmq[l][k],rmq[r-(1<<k)+1][k]);
}
void init(int n)
{
int tot = log(n*1.0)/log(2.0);
int j = -1;
int x = 1;
cs[0] = 0;
b.clear();
a.clear();
for(int k = 0; k <= tot; ++k)
{
for(int i = 0; i < n && (i+(1<<k)) <= n; ++i)
{
if(!k)
{
scanf("%d",&rmq[i][k]);
if(i+1 == x)
{
x <<= 1;
j++;
}
cs[i+1] = j;
//int ssss = log((i+1)*1.0)/log(2.0);
//printf("%d %d %d\n",i+1,cs[i+1],ssss);
tmp.clear();
for(iter = a.begin(); iter != a.end(); ++iter)
{
int g = __gcd(iter->first,rmq[i][0]);
tmp[g] += iter->second;
}
tmp[rmq[i][0]]++;
a = tmp;
for(iter = a.begin(); iter != a.end(); ++iter)
b[iter->first] += iter->second;
}
else rmq[i][k] = __gcd(rmq[i][k-1],rmq[i+(1<<(k-1))][k-1]);
}
}
}
int main()
{
//fread("");
//fwrite("");
int t,n;
int z = 1;
scanf("%d",&t);
while(t--)
{
printf("Case #%d:\n",z++);
scanf("%d",&n);
init(n);
int q;
scanf("%d",&q);
int l,r;
while(q--)
{
scanf("%d%d",&l,&r);
int g = Search(l-1,r-1);
printf("%d %lld\n",g,b[g]);
}
}
return 0;
}