杭州未能取得奖项真是千古恨啊。赛后和学长讨论了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; }