[美团 CodeM 初赛 Round A]数列互质

题目大意:
  给出一个长度为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 }

 

转载于:https://www.cnblogs.com/skylee03/p/8124949.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值