给一串数列,求区间GCD和整个数列中与该区间GCD相等的区间数
首先区间GCD易求,用能求RMQ的方法都可以,比如ST表、线段树。关键是如何求第二个问题,这里有两种做法:
方法一
利用GCD的性质,若固定区间左端点,增大右端点,区间GCD必然非递增。因此我们可以遍历区间左端点,用二分求出以该端点起始的区间的所有gcd的情况及其对应的区间个数,并用map记录。该过程复杂度可近似看做 O(nlogn) 。写线段树有可能会T,最好写ST表。
方法二
用map暴力枚举。从左向右遍历,用两个map,一个存答案也就是某种gcd的个数,另一个存以当前位置结尾的所有区间的gcd情况。每向右移动一次,就将这个新元素与前一个位置结尾的情况全部gcd一遍,更新存答案的map,同时也更新另一个map
//HDU 5726 GCD
//AC 2017-1-17 19:21:30
//Sparse table, GCD, Binary Search
#include
using namespace std;
const int maxn=1e5+100;
int N;
long long a[maxn];
long long ST[maxn][30];
void ST_init()
{
for(int i=1;i<=N;++i)
ST[i][0]=a[i];
for(int j=1;j<30;++j)
{
for(int i=1;i<=N;++i)
{
if(i+(1<1>N) break;
ST[i][j]=__gcd(ST[i][j-1],ST[i+(1<<(j-1))][j-1]);
}
}
return;
}
long long ST_query(int s,int e)
{
int k=(int)((log(e-s+1.0)/log(2.0)));
return __gcd(ST[s][k],ST[e-(1<1][k]);
}
map<long long,long long> ans;
void setTable()
{
ans.clear();
for(int i=1;i<=N;i++)
{
int g=ST[i][0],j=i;
while(j<=N)
{
int l=j,r=N;
while(lint mid=(l+r+1)>>1;
if(ST_query(i,mid)==g) l=mid;
else r=mid-1;
}
ans[g]+=l-j+1;
j=l+1;
g=ST_query(i,j);
}
}
}
int main()
{
int T;scanf("%d",&T);
for(int kase=1;kase<=T;++kase)
{
scanf("%d",&N);
for(int i=0;iscanf("%lld",a+i+1);
ST_init();
setTable();
int Q;
scanf("%d",&Q);
int l,r;
printf("Case #%d:\n",kase);
while(Q--)
{
scanf("%d %d",&l,&r);
long long gcd=ST_query(l,r);
printf("%lld %lld\n",gcd,ans[gcd]);
}
}
return 0;
}
#include
using namespace std;
const int maxn=1e5+100;
int N;
long long a[maxn];
struct segTree
{
long long gcd[maxn*4];
void Push_Up(int x)
{
gcd[x]=__gcd(gcd[x<<1],gcd[x<<1|1]);
return;
}
void build(int x,int l,int r)
{
if(l==r)
{
gcd[x]=a[l];
return;
}
int mid=(l+r)>>1;
build(x<<1,l,mid);
build(x<<1|1,mid+1,r);
Push_Up(x);
return;
}
long long query(int x,int beg,int endd,int l,int r)
{
if(l==beg&&r==endd)
return gcd[x];
int mid=(l+r)>>1;
if(beg>mid)
return query(x<<1|1,beg,endd,mid+1,r);
else if(endd<=mid)
return query(x<<1,beg,endd,l,mid);
else
return __gcd(query(x<<1,beg,mid,l,mid),query(x<<1|1,mid+1,endd,mid+1,r));
}
}Tree;
map<long long,long long> ans;
map<long long,long long> mp1;
map<long long,long long> mp2;
int main()
{
int T;scanf("%d",&T);
for(int kase=1;kase<=T;++kase)
{
scanf("%d",&N);
for(int i=0;iscanf("%lld",a+i+1);
Tree.build(1,1,N);
ans.clear();mp1.clear();mp2.clear();
mp1[a[1]]++;ans[a[1]]++;
for(int i=2;i<=N;++i)
{
mp2[a[i]]++;
ans[a[i]]++;
for(map<long long,long long>::iterator ita=mp1.begin();ita!=mp1.end();++ita)
{
long long now=__gcd(a[i],ita->first);
ans[now]+=ita->second;
mp2[now]+=ita->second;
}
swap(mp1,mp2);
mp2.clear();
}
int Q;
scanf("%d",&Q);
int l,r;
printf("Case #%d:\n",kase);
while(Q--)
{
scanf("%d %d",&l,&r);
long long gcd=Tree.query(1,l,r,1,N);
printf("%lld %lld\n",gcd,ans[gcd]);
}
}
return 0;
}