n rabbits were numbered form 1 to n. All rabbits' weight is an integer. For some unknown reason, two rabbits would fight each other if and only if their weight is NOT co-prime.
Now the king had arranged the n rabbits in a line ordered by their numbers. The king planned to send some rabbits into prison. He wanted to know that, if he sent all rabbits between the i-th one and the j-th one(including the i-th one and the j-th one) into prison, how many rabbits in the prison would not fight with others.
Please note that a rabbit would not fight with himself.
The first line of each test case contains two integer n, m, indicating the number of rabbits and the queries.
The following line contains n integers, and the i-th integer Wi indicates the weight of the i-th rabbit.
Then m lines follow. Each line represents a query. It contains two integers L and R, meaning the king wanted to ask about the situation that if he sent all rabbits from the L-th one to the R-th one into prison.
(1 <= n, m, Wi <= 200000, 1 <= L <= R <= n)
The input ends with n = 0 and m = 0.
3 2 2 1 4 1 2 1 3 6 4 3 6 1 2 5 3 1 3 4 6 4 4 2 6 0 0
2 1 1 3 1 2HintIn the second case, the answer of the 4-th query is 2, because only 1 and 5 is co-prime with other numbers in the interval [2,6] .
先算出每个数的有效范围,l[i],r[i]代表与第i个数一直互质到的最左端和最右端。这个处理方法是,预处理出一张因子表。然后对每个输入的数,判断其因子出现的最接近它的位置。从左到右扫一遍求出l[i],从右到左扫一遍求出r[i];我们还需要用一个vector记录下左边界为i时的所有数。
我们思考一个范围内,当一个数的l[i]和r[i]都在范围之外时,这个数会被统计在内。反过来讲就是一个范围在一个数的边界之内,当前的数会被统计到范围之内。
我们先对问题进行离线处理,先根据问题的左边界排序。我们需要维护一个树状数组来统计和增减值。
然后我们按照i从1到n扫一遍,i代表的意义是左边界。
1. 当扫到第i个数时,我们统计左边界为i+1的问题(这样范围一定满足左边界,因为右边界接下来也进行了处理,所以可以直接统计)。
2. 我们还需要更新第i个数。i的意义是左边界,因为之后统计的问题左边界都大于i,都满足。所以我们找到所有左边界为i的数,将其+1处理。然后右边界-1处理。这样如果问题的边界大于右边界的话,这个数就不会统计在内。
3. 最后处理完i后,因为以后问题的左边界都大于i,所以第i个数不会再被统计了,所以我们要除去第i个数的影响,就是把其右边界+1(自身为什么不处理,因为处不处理都一样,不会在涉及到它本身了)。
感觉想起来挺复杂的,还是看代码清晰。
#include <iostream>
#include<bits/stdc++.h>
using namespace std;
const int N=220000;
int p[N],pnum,tree[N],n,m,l[N],r[N],a[N],ans[N],last[N];
vector<int>vec[N],pl[N];
void init()
{
memset(p,0,sizeof(p));
for(int i=2;i<=200000;i++)
if(!p[i])
{
for(int j=i;j<=200000;j+=i)
{
p[j]=1;
vec[j].push_back(i);
}
}
}
struct node
{
int l,r,i;
}q[N];
bool cmp(node a,node b)
{
return a.l<b.l;
}
void find_l()
{
memset(last,0,sizeof(last));
for(int i=0;i<=n;i++) pl[i].clear();
for(int i=1;i<=n;i++)
{
int mmax=0;
for(int j=0;j<vec[a[i]].size();j++)
{
int t=vec[a[i]][j];
if(last[t]>mmax) mmax=last[t];
last[t]=i;
}
l[i]=mmax;
pl[mmax].push_back(i);
}
}
void find_r()
{
memset(last,-1,sizeof(last));
for(int i=n;i>=0;i--)
{
int mmin=n+1;
for(int j=0;j<vec[a[i]].size();j++)
{
int t=vec[a[i]][j];
if(last[t]!=-1&&last[t]<mmin) mmin=last[t];
last[t]=i;
}
r[i]=mmin;
}
}
void add(int k,int num)
{
while(k<=n)
{
tree[k]+=num;
k+=k&-k;
}
}
int sum(int k)
{
int ans=0;
while(k)
{
ans+=tree[k];
k-=k&-k;
}
return ans;
}
int main()
{
init();
while(~scanf("%d%d",&n,&m)&&n+m)
{
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=m;i++) scanf("%d%d",&q[i].l,&q[i].r),q[i].i=i;;
sort(q+1,q+m+1,cmp);
find_l();
find_r();
int cnt=1;
for(int i=1;i<=n;i++) tree[i]=0;
for(int i=0;i<=n;i++)
{
while(cnt<=m&&q[cnt].l==i)
{
ans[q[cnt].i]=sum(q[cnt].r)-sum(q[cnt].l-1);
cnt++;
}
for(int j=0;j<pl[i].size();j++)
{
add(pl[i][j],1);
add(r[pl[i][j]],-1);
}
add(r[i],1);
}
for(int i=1;i<=m;i++) printf("%d\n",ans[i]);
}
}