您的位置:首页 > 其它

BZOJ 2038 小Z的袜子 莫队算法

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

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

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

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

我大致是这样做的:

1、分块

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

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

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

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

View Code

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cmath>

#define N 55555

using namespace std;

struct Q
{
long long l,r,id;
}q
;

struct ANS
{
long long a,b;
void in(long long x,long long y) {a=x,b=y;}
}ans
;

long long col
,n,m,gs
;
long long lt
,rt
,len,tot;

inline bool cmpl(const Q &a,const Q &b)
{
return a.l<b.l;
}

inline bool cmpr(const Q &a,const Q &b)
{
return a.r<b.r;
}

inline void read()
{
scanf("%lld%d",&n,&m);
for(long long i=1;i<=n;i++) scanf("%lld",&col[i]);
for(long long i=1;i<=m;i++)
{
scanf("%lld%d",&q[i].l,&q[i].r);
q[i].id=i;
}
len=(long long)sqrt(1.0*n);
tot=n/len;
for(long long i=1;i<=tot;i++) lt[i]=rt[i-1]+1,rt[i]=rt[i-1]+len;
if(rt[tot]!=n) lt[tot+1]=rt[tot]+1,rt[tot+1]=n,tot++;
}

inline long long gcd(long long x,long long y)
{
long long ys;
while(y)
{
ys=x%y;
x=y; y=ys;
}
return x;
}

inline void getans(long long x,long long ml)
{
long long sum=(q[x].r-q[x].l)*(q[x].r-q[x].l+1)/2;
long long mx=gcd(ml,sum);
if(!mx) ans[q[x].id].in(0,1);
else ans[q[x].id].in(ml/mx,sum/mx);
}

inline void go()
{
sort(q+1,q+m+1,cmpl);
long long s=1,t=1;
for(long long i=1,ml=0;i<=tot;i++,ml=0)
{
memset(gs,0,sizeof gs);
while(s<=m&&q[s].l<lt[i]) s++;
while(t<=m&&q[t].l<=rt[i]) t++;
if(s>m||q[s].l>rt[i]) continue;
sort(q+s,q+t,cmpr);
for(long long j=q[s].l;j<=q[s].r;j++) ml+=gs[col[j]],gs[col[j]]++;
getans(s,ml);
for(long long j=s+1;j<t;j++)
{
if(q[j].l<q[j-1].l)
{
for(long long k=q[j].l;k<q[j-1].l;k++) ml+=gs[col[k]],gs[col[k]]++;
for(long long k=q[j-1].r+1;k<=q[j].r;k++) ml+=gs[col[k]],gs[col[k]]++;
}
else if(q[j].l>q[j-1].r)
{
for(long long k=q[j-1].l;k<=q[j-1].r;k++) gs[col[k]]--;
ml=0;
for(long long k=q[j].l;k<=q[j].r;k++) ml+=gs[col[k]],gs[col[k]]++;
}
else
{
for(long long k=q[j-1].l;k<q[j].l;k++) gs[col[k]]--,ml-=gs[col[k]];
for(long long k=q[j-1].r+1;k<=q[j].r;k++) ml+=gs[col[k]],gs[col[k]]++;
}
getans(j,ml);
}
}
for(long long i=1;i<=m;i++) printf("%lld/%lld\n",ans[i].a,ans[i].b);
}

int main()
{
read(),go();
return 0;
}


这个莫队算法是处理区间无修改询问的通用算法??
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: