杭州未能取得奖项真是千古恨啊。赛后和学长讨论了H题。写了下。
思路:对于每个数求出它能互质的前范围和后范围。然后用树状数组离线处理询问。对于每个询问,其结果是 前范围和后范围包含询问区间的个数减去前范围到下标-1包含询问区间的个数减去下标+1到后范围包含询问区间的个数。
由于没地交,我也不知道能不能AC。。。。。。(hdu已ac)
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int p[200010];
struct node
{
int l,z,r;
}t[200010];
struct query
{
int l,r,num;
}q[200010];
int c[200010],s1[200010],s2[200010],s3[200010];
int m,n,a[200010],d[200010];
void prime()
{
memset(p,0,sizeof(p));
p[1]=1;
for(int i=2;i<=200000;i++)
{
if(p[i]==0)
{
for(int j=i;j<=200000;j+=i)p[j]=i;
}
}
}
bool cmpq(query x,query y)
{
return x.l<y.l;
}
bool cmp1(node x,node y)
{
return x.l<y.l;
}
bool cmp2(node x,node y)
{
return x.z<y.z;
}
int lowbit(int x)
{
return x&(-x);
}
void add(int w,int v)
{
for(int i=w;i<=n;i+=lowbit(i))
{
c[i]+=v;
}
}
int sum(int w)
{
int s=0;
for(int i=w;i>=1;i-=lowbit(i))
{
s+=c[i];
}
return s;
}
int main()
{
prime();
while(scanf("%d%d",&n,&m))
{
if(m==0&&n==0)break;
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].num=i;
}
memset(d,0,sizeof(d));
for(int i=1;i<=n;i++)
{
int mm=1;
t[i].z=i;
for(int j=a[i];j!=1;j=j/p[j])
{
if(d[p[j]]+1>mm&&d[p[j]]!=i)
{
mm=d[p[j]]+1;
}
d[p[j]]=i;
}
t[i].l=mm;
}
for(int i=0;i<=200000;i++)d[i]=n+1;
for(int i=n;i>=1;i--)
{
int mm=n;
for(int j=a[i];j!=1;j=j/p[j])
{
if(d[p[j]]-1<mm&&d[p[j]]!=i)
{
mm=d[p[j]]-1;
}
d[p[j]]=i;
}
t[i].r=mm;
}
sort(q+1,q+m+1,cmpq);
memset(c,0,sizeof(c));
sort(t+1,t+n+1,cmp1);
int w=1;
for(int i=1;i<=m;i++)
{
for(;w<=n;w++)
{
if(t[w].l>q[i].l)break;
add(t[w].l,1);
add(t[w].r+1,-1);
}
s1[q[i].num]=sum(q[i].r);
}
memset(c,0,sizeof(c));
w=1;
for(int i=1;i<=m;i++)
{
for(;w<=n;w++)
{
if(t[w].l>q[i].l)break;
add(t[w].l,1);
add(t[w].z,-1);
}
s2[q[i].num]=sum(q[i].r);
}
memset(c,0,sizeof(c));
sort(t+1,t+n+1,cmp2);
w=1;
for(int i=1;i<=m;i++)
{
for(;w<=n;w++)
{
if(t[w].z>=q[i].l)break;
add(t[w].z,1);
add(t[w].r+1,-1);
}
s3[q[i].num]=sum(q[i].r);
}
for(int i=1;i<=m;i++)
{
printf("%d\n",s1[i]-s2[i]-s3[i]);
}
}
return 0;
}