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 }

 

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

 

 

posted @ 2013-03-03 20:48  proverbs  阅读(2523)  评论(0编辑  收藏  举报