题目大意:
给出一个长度为n的数列a1,a2,a3,...,an,以及m组询问(li,ri,ki),求区间[li,ri]中有多少数在该区间中的出现次数与ki互质。
思路:
莫队。
f[i]记录数字i出现的次数,用一个链表记录f[i]的出现次数。
一开始没用链表,用map,在SimpleOJ上随便A,但是在LOJ上只有50分。
1 #include<cmath> 2 #include<cstdio> 3 #include<cctype> 4 #include<algorithm> 5 inline int getint() { 6 register char ch; 7 while(!isdigit(ch=getchar())); 8 register int x=ch^'0'; 9 while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0'); 10 return x; 11 } 12 const int N=50001,M=50000; 13 int a[N],f[N],ans[M],block; 14 struct Question { 15 int l,r,k,id; 16 bool operator < (const Question &another) const { 17 return l/block==another.l/block?r/block<another.r/block:l/block<another.l/block; 18 } 19 }; 20 Question q[M]; 21 struct List { 22 int val[N],last[N],next[N],end; 23 int &operator [] (const int &p) { 24 return val[p]; 25 } 26 void insert(const int &x) { 27 next[end]=x; 28 last[x]=end; 29 end=x; 30 } 31 void erase(const int &x) { 32 if(x==end) end=last[x]; 33 next[last[x]]=next[x]; 34 last[next[x]]=last[x]; 35 val[x]=last[x]=next[x]=0; 36 } 37 }; 38 List list; 39 inline void insert(const int &x) { 40 if(f[x]&&!--list[f[x]]) list.erase(f[x]); 41 if(!list[++f[x]]) list.insert(f[x]); 42 list[f[x]]++; 43 } 44 inline void erase(const int &x) { 45 if(!--list[f[x]]) list.erase(f[x]); 46 if(--f[x]) { 47 if(!list[f[x]]) list.insert(f[x]); 48 list[f[x]]++; 49 } 50 } 51 int gcd(const int &a,const int &b) { 52 return b?gcd(b,a%b):a; 53 } 54 int main() { 55 const int n=getint(),m=getint(); 56 block=sqrt(m); 57 for(register int i=1;i<=n;i++) a[i]=getint(); 58 for(register int i=0;i<m;i++) { 59 q[i]=(Question){getint(),getint(),getint(),i}; 60 } 61 std::sort(&q[0],&q[m]); 62 for(register int i=0,l=1,r=0;i<m;i++) { 63 while(l>q[i].l) insert(a[--l]); 64 while(r<q[i].r) insert(a[++r]); 65 while(l<q[i].l) erase(a[l++]); 66 while(r>q[i].r) erase(a[r--]); 67 for(register int j=list.end;j;j=list.last[j]) { 68 if(gcd(j,q[i].k)==1) ans[q[i].id]+=list[j]; 69 } 70 } 71 for(register int i=0;i<m;i++) { 72 printf("%d\n",ans[i]); 73 } 74 return 0; 75 }