题目描述
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].
算法思路
- 一般查询模式有两种模式,我想他们是和CS模式一一对应的,即离线算法和在线算法。在线算法指的是我们来一个查询就返回一个查询。很显然,一般应用在我们的知识数据库不再需要大量改动的时候。而对于离线算法,我们将所有的查询储存下来,然后在查询的过程中我们可能还要更新查询的数据库,来获得后面的解。
- 这一题就是典型的离线算法,我们固定按顺序求出每一个右端点和其之前的元素可能构造出来的gcd,并且储存其左端点,然后将每一个查询按照右端点从小到大的顺序储存下来,那么,在查询的过程中,对于一个gcd,如果前面的子数组也产生了同样的gcd,那么就更新,对一个右端点更新完成之后在查询。
- 查询的数据结构多种多样,树状数组,线段树,随便选择都好
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<cstring>
#include<utility>
using namespace std;
#define MAXN 100005
int Arr[MAXN];
int N,Q;
int pos[MAXN*10];
vector<pair<int,int> >queryS[MAXN];
vector<pair<int,int> >gcdS[MAXN];
int ans[MAXN];
int treeArr[MAXN];
int gcd(int a,int b)
{
if(!(a%b))return b;
else return gcd(b,a%b);
}
void Init()
{
int i,tmp,ts,j;
for(i=1;i<=N;i++){
tmp = Arr[i];
ts = i;
for(j=0;j<gcdS[i-1].size();j++){
int tmpgcd = gcd(tmp,gcdS[i-1][j].first);
if(tmpgcd != tmp){
gcdS[i].push_back(make_pair(tmp,ts));
ts = gcdS[i-1][j].second;
tmp = tmpgcd;
}
}
gcdS[i].push_back(make_pair(tmp,ts));
}
return;
}
void Add(int cur,int num)
{
int k = cur;
while(k<=N){
treeArr[k] += num;
k += k&(-k);
}
return;
}
int Query(int cur)
{
int k = cur,sum = 0;
while(k){
sum += treeArr[k];
k -= k&(-k);
}
return sum;
}
void Solve()
{
memset(pos,0,sizeof(pos));
memset(treeArr,0,sizeof(treeArr));
int i,j;
for(i=1;i<=N;i++){
for(j=0;j<gcdS[i].size();j++){
if(pos[gcdS[i][j].first]){
//update
Add(pos[gcdS[i][j].first],-1);
}
Add(gcdS[i][j].second,1);
pos[gcdS[i][j].first] = gcdS[i][j].second;
}
for(j=0;j<queryS[i].size();j++){
ans[queryS[i][j].second] = Query(i)-Query(queryS[i][j].first-1);
}
}
for(i=1;i<=Q;i++)
printf("%d\n",ans[i]);
return;
}
int main()
{
freopen("input","r",stdin);
int i,tmp1,tmp2;
while(scanf("%d%d",&N,&Q)!=EOF){
for(i=1;i<=N;i++){
scanf("%d",&Arr[i]);
queryS[i].clear();
gcdS[i].clear();
}
Init();
for(i=1;i<=Q;i++){
//using vector to sort the query
//by the end index
//
scanf("%d%d",&tmp1,&tmp2);
queryS[tmp2].push_back(make_pair(tmp1,i));
}
Solve();
}
return 0;
}