Different GCD Subarray Query
Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 999 Accepted Submission(s): 381
Problem Description
This is a simple problem. The teacher gives Bob a list of problems about GCD (Greatest Common Divisor). After studying some of them, Bob thinks that GCD is so interesting. One day, he comes up with a new problem about GCD. Easy as it looks, Bob cannot figure it out himself. Now he turns to you for help, and here is the problem:
Given an array a of N positive integers a1,a2,⋯aN−1,aN; a subarray of a is defined as a continuous interval between a1 and aN. In other words, ai,ai+1,⋯,aj−1,aj is a subarray of a, for 1≤i≤j≤N. For a query in the form (L,R), tell the number of different GCDs contributed by all subarrays of the interval [L,R].
Input
There are several tests, process till the end of input.
For each test, the first line consists of two integers N and Q, denoting the length of the array and the number of queries, respectively. N positive integers are listed in the second line, followed by Q lines each containing two integers L,R for a query.
You can assume that
1≤N,Q≤100000
1≤ai≤1000000
Output
For each query, output the answer in one line.
Sample Input
5 3 1 3 4 6 9 3 5 2 5 1 5
Sample Output
6 6 6
Source
2016 ACM/ICPC Asia Regional Dalian Online
Recommend
wange2014 | We have carefully selected several similar problems for you: 5900 5899 5897 5896 5895
题意:n个数,m个询问,每次询问一段区间的不同gcd的个数。
分析:因为给的n的范围是(1-100000),所以直接处理所有区间是很难的。所以我们可以先把询问保存起来,然后根据r排序。
这样我们就可以通过数状数组,维护一个以i为结尾的一个数组中有多少不同gcd,然后接下来重点是怎么更新了。
首先我们可以预处理出以每个子区间(以当前节点为结尾)的gcd,然后我们可以记录下在增加这个节点前,当前gcd值的所在点,然后更新,我们要尽可能的把相关的
记录位置右移(也就是成立gcd的子区间的左端点),这里就是简单的数状数组单点更新了。
代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 10;
int h[maxn],sum[maxn*4];
int sign[maxn*10];
int ans[maxn];
vector <pair <int,pair <int,int> > > v[maxn];
struct node
{
int l,r;
int loc;
} s[maxn];
int lowbit(int x)
{
return x & (-x);
}
void add(int x, int num,int N)
{
while(x <= N)
{
sum[x] += num;
x += lowbit(x);
}
}
int query(int x)
{
if(!x) return 0;
return sum[x] + query(x - lowbit(x));
}
bool cmp(node as,node zx)
{
if(as.r!=zx.r)
return as.r<zx.r;
else return as.l<zx.l;
}
void solve(int n,int m)
{
int last=0;
for(int i=1; i<=m; i++)
{
if(s[i].r<=last)
{
ans[s[i].loc]=query(s[i].r)-query(s[i].l-1);
}
else
{
for(int j=last+1; j<=s[i].r; j++)
{
for(int k=0; k<v[j].size(); k++)
{
if(v[j][k].second.first)
add(v[j][k].second.first,-1,n);
add(v[j][k].second.second,1,n);
}
}
last=s[i].r;
i--;
}
}
}
int main()
{
int n,m;
while(~scanf("%d%d",&n, &m))
{
memset(sign,0,sizeof(sign));
memset(sum,0,sizeof(sum));
for(int i=1; i<=n; i++)//预处理部分
{
v[i].clear();
scanf("%d",&h[i]);
for(int j=0; j<v[i-1].size(); j++)
{
int x=__gcd(v[i-1][j].first,h[i]);
v[i].push_back(make_pair(x,make_pair(sign[x],v[i-1][j].second.second)));
sign[x]=v[i-1][j].second.second;
for(int k=0; k<v[i].size()-1; k++)
{
if(v[i][k].first==x)
{
v[i][v[i].size()-1].second.first=v[i][k].second.first;
v[i].erase(v[i].begin()+k);
k--;
}
}
}
v[i].push_back(make_pair(h[i],make_pair(sign[h[i]],i)));
sign[h[i]]=i;
for(int k=0; k<v[i].size()-1; k++)//要不之前的相同gcd值点删除,不然极限状态下会爆内存
{
if(v[i][k].first==h[i])
{
v[i][v[i].size()-1].second.first=v[i][k].second.first;
v[i].erase(v[i].begin()+k);
k--;
}
}
}
for(int i=1; i<=m; i++)
{
scanf("%d%d",&s[i].l,&s[i].r);
s[i].loc=i;
}
sort(s+1,s+1+m,cmp);
solve(n,m);
for(int i=1; i<=m; i++)
{
printf("%d\n",ans[i]);
}
}
return 0;
}