BZOJ 2038 小Z的袜子 莫队算法

题解:
区间总的方案数是可以算的,只要求相同的颜色的方案数即可。(数学中讲的古典概型??)

 

我不知道我写的是不是莫队算法,时间还是很快的。。

话说,这题稍微优化的暴力也能过。

 

看了别人的介绍莫队算法的文章没有看太懂,也不知道这个神奇的复杂度是怎么证明的。。。

我大致是这样做的:

1、分块

2、把所有询问左端点排序

3、对于左端点在同一块内的询问按右端点排序,然后分三种情况统计。

 

传说中这样复杂度是nsqrt(n)的,但是我怎么觉得这个和我的暴力差不多。。。。

莫名其妙跑的这么快。。。

 

View Code
  1 #include <iostream>

  2 #include <cstring>

  3 #include <cstdio>

  4 #include <cstdlib>

  5 #include <algorithm>

  6 #include <cmath>

  7 

  8 #define N 55555

  9 

 10 using namespace std;

 11 

 12 struct Q

 13 {

 14     long long l,r,id;

 15 }q[N];

 16 

 17 struct ANS

 18 {

 19     long long a,b;

 20     void in(long long x,long long y) {a=x,b=y;}

 21 }ans[N];

 22 

 23 long long col[N],n,m,gs[N];

 24 long long lt[N],rt[N],len,tot;

 25 

 26 inline bool cmpl(const Q &a,const Q &b)

 27 {

 28     return a.l<b.l;

 29 }

 30 

 31 inline bool cmpr(const Q &a,const Q &b)

 32 {

 33     return a.r<b.r;

 34 }

 35 

 36 inline void read()

 37 {

 38     scanf("%lld%d",&n,&m);

 39     for(long long i=1;i<=n;i++) scanf("%lld",&col[i]);

 40     for(long long i=1;i<=m;i++)

 41     {

 42         scanf("%lld%d",&q[i].l,&q[i].r);

 43         q[i].id=i;

 44     }

 45     len=(long long)sqrt(1.0*n);

 46     tot=n/len;

 47     for(long long i=1;i<=tot;i++) lt[i]=rt[i-1]+1,rt[i]=rt[i-1]+len;

 48     if(rt[tot]!=n) lt[tot+1]=rt[tot]+1,rt[tot+1]=n,tot++;

 49 }

 50 

 51 inline long long gcd(long long x,long long y)

 52 {

 53     long long ys;

 54     while(y)

 55     {

 56         ys=x%y;

 57         x=y; y=ys;

 58     }

 59     return x;

 60 }

 61 

 62 inline void getans(long long x,long long ml)

 63 {

 64     long long sum=(q[x].r-q[x].l)*(q[x].r-q[x].l+1)/2;

 65     long long mx=gcd(ml,sum);

 66     if(!mx) ans[q[x].id].in(0,1);

 67     else ans[q[x].id].in(ml/mx,sum/mx);

 68 }

 69 

 70 inline void go()

 71 {

 72     sort(q+1,q+m+1,cmpl);

 73     long long s=1,t=1;

 74     for(long long i=1,ml=0;i<=tot;i++,ml=0)

 75     {

 76         memset(gs,0,sizeof gs);

 77         while(s<=m&&q[s].l<lt[i]) s++;

 78         while(t<=m&&q[t].l<=rt[i]) t++;

 79         if(s>m||q[s].l>rt[i]) continue;

 80         sort(q+s,q+t,cmpr);

 81         for(long long j=q[s].l;j<=q[s].r;j++) ml+=gs[col[j]],gs[col[j]]++;

 82         getans(s,ml);

 83         for(long long j=s+1;j<t;j++)

 84         {

 85             if(q[j].l<q[j-1].l)

 86             {

 87                 for(long long k=q[j].l;k<q[j-1].l;k++) ml+=gs[col[k]],gs[col[k]]++;

 88                 for(long long k=q[j-1].r+1;k<=q[j].r;k++) ml+=gs[col[k]],gs[col[k]]++;

 89             }

 90             else if(q[j].l>q[j-1].r)

 91             {

 92                 for(long long k=q[j-1].l;k<=q[j-1].r;k++) gs[col[k]]--;

 93                 ml=0;

 94                 for(long long k=q[j].l;k<=q[j].r;k++) ml+=gs[col[k]],gs[col[k]]++;

 95             }

 96             else

 97             {

 98                 for(long long k=q[j-1].l;k<q[j].l;k++) gs[col[k]]--,ml-=gs[col[k]];

 99                 for(long long k=q[j-1].r+1;k<=q[j].r;k++) ml+=gs[col[k]],gs[col[k]]++;

100             }

101             getans(j,ml);

102         }

103     }

104     for(long long i=1;i<=m;i++) printf("%lld/%lld\n",ans[i].a,ans[i].b);

105 }

106 

107 int main()

108 {

109     read(),go();

110     return 0;

111 }

 

这个莫队算法是处理区间无修改询问的通用算法??

 

 

你可能感兴趣的:(ZOJ)