GCD
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 5368 Accepted Submission(s): 1936
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
Author
HIT
Source
2016 Multi-University Training Contest 1
区间gcd有一个很强的性质,
任何一个区间不同的GCD个数是log级别的,因为随着右端点向右延伸GCD是单调不增的,而每次递减GCD至少除以2。
考虑固定左端点,最多就nlogn种GCD,可以直接把所有区间GCD值预处理出来,用map存储各种GCD值的个数,查询时直接输出。
所以这里既可以用ST表处理出ST[ i ][ j ] 表示从i开始长度为2的j次方的区间的gcd ,然后再固定左端点,进行若干次二分右端点,就可以求出所有的gcd,当然也可以用线段树来维护。
还有就是可以dp一下,dp[i][j] 表示的是以第i个结尾的最大公约数为j 的个数。
ST 代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N =1e5+5;
int ST[N][21];
int yi[25];
int a[N];
int n;
map<int ,ll >mp;
void init_yi()
{
yi[0]=1;
for(int i=1;i<=21;i++) yi[i]=yi[i-1]*2;
}
void init_ST()
{
for(int i=1;i<=n;i++) ST[i][0]=a[i];
for(int k=1;k<=19;k++)
{
for(int i=1;i<=n;i++)
{
if(i+yi[k]-1<=n){
ST[i][k]=__gcd(ST[i][k-1],ST[i+yi[k-1]][k-1]);
}
}
}
}
int jud(int l,int r)
{
int k=(int)log2((double)(r-l+1));
return __gcd(ST[l][k],ST[r-yi[k]+1][k]);
}
void init_mp()
{
mp.clear();
for(int i=1;i<=n;i++)
{
int now=a[i];
int lb=i;
int pos=i;
while(pos<=n)
{
int l,r,mid;
l=pos; r=n;
int ans;
while(l<=r)
{
mid=(l+r)>>1;
if(jud(lb,mid)==now){
ans=mid;
l=mid+1;
}
else r=mid-1;
}
mp[now]+=1ll*(ans-pos+1);
pos=ans+1;
now=jud(lb,pos);
}
}
}
int main()
{
init_yi();
int T,kk;
kk=0;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
init_ST();
init_mp();
int k;
printf("Case #%d:\n",++kk);
scanf("%d",&k);
int l,r;
while(k--)
{
scanf("%d %d",&l,&r);
int ans=jud(l,r);
printf("%d %lld\n",ans,mp[ans]);
}
}
return 0;
}
dp代码:
#include<bits/stdc++.h>
#define lson (i<<1)
#define rson (i<<1|1)
using namespace std;
typedef long long ll;
const int N =1e5+5;
map<int ,ll > ans;
map<int ,ll > dp[N]; /// dp[i][j] 表示的是以第i个结尾的最大公约数为j 的个数。
map<int ,ll >::iterator it;
int a[N];
struct node
{
int l,r;
int val;
}tr[N<<2];
int n;
void push_up(int i)
{
tr[i].val=__gcd(tr[lson].val,tr[rson].val);
}
void build(int i,int l,int r)
{
tr[i].l=l; tr[i].r=r; tr[i].val=0;
if(l==r){
tr[i].val=a[l];
return ;
}
int mid=(l+r)>>1;
build(lson,l,mid);
build(rson,mid+1,r);
push_up(i);
}
int query(int i,int l,int r)
{
if(tr[i].l==l&&tr[i].r==r) return tr[i].val;
int mid=(tr[i].l+tr[i].r)>>1;
if(r<=mid) return query(lson,l,r);
else if(l>mid) return query(rson,l,r);
else{
return __gcd(query(lson,l,mid),query(rson,mid+1,r));
}
}
int main()
{
int T;
scanf("%d",&T);
int kk=0;
while(T--)
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
build(1,1,n);
for(int i=0;i<=n;i++) dp[i].clear();
ans.clear();
dp[1][a[1]]+=1;
ans[a[1]]+=1;
for(int i=2;i<=n;i++){
dp[i][a[i]]+=1; ans[a[i]]+=1;
for(it=dp[i-1].begin();it!=dp[i-1].end();it++){
int gcd=__gcd(it->first,a[i]);
dp[i][gcd]+=it->second;
ans[gcd]+=it->second;
}
}
int k,l,r;
scanf("%d",&k);
printf("Case #%d:\n",++kk);
while(k--)
{
scanf("%d %d",&l,&r);
int gcd=query(1,l,r);
printf("%d %lld\n",gcd,ans[gcd]);
}
}
return 0;
}