bzoj2038 小Z的袜子【莫队算法模板+详解】
来源:互联网 发布:linux json 编辑:程序博客网 时间:2024/05/17 03:02
解题思路:
莫队出的模板题。
如果我们知道了询问区间中每种颜色的数量
关键是如何快速统计区间内每种颜色的数量,这就要用到莫队算法。
考虑建立两个指针l,r,表示区间[l,r]内每种颜色的数量已知。
再将询问离线,按询问左端点所在块(块大小为
先考虑左指针。
当询问左端点在同一块时,每次挪动不超过
再考虑右指针。
当询问左端点在同一块时,询问右端点单调递增,一块内最多移动n次;当换块时,右指针最多从n挪回1,也是n次;而整个区间最多会被分为
综上,莫队算法的时间复杂度是
其实还有带修改的莫队,可以做做bzoj2120,
题解详见http://blog.csdn.net/cdsszjj/article/details/78397256
#include<bits/stdc++.h>using namespace std;int read(){ int i=0,f=1;char c; for(c=getchar();(c<'0'||c>'9')&&c!='-';c=getchar()); if(c=='-')f=-1,c=getchar(); for(;c>='0'&&c<='9';c=getchar())i=(i<<3)+(i<<1)+c-'0'; return i*f;}const int N=50005;int n,m,S,a[N],cnt[N];struct node{ int l,r,id,block; inline friend bool operator < (const node &a,const node &b) {return a.block<b.block||a.block==b.block&&a.r<b.r;}}q[N];pair<int,int>ans[N];int gcd(int a,int b){ return b?gcd(b,a%b):a;}int calc(int x){ return 1ll*x*(x-1)/2;}int main(){ //freopen("lx.in","r",stdin); n=read(),m=read(),S=sqrt(n); for(int i=1;i<=n;i++)a[i]=read(); for(int i=1;i<=m;i++) { q[i].l=read(),q[i].r=read(),q[i].id=i; q[i].block=(q[i].l-1)/S+1; } sort(q+1,q+m+1); int l=1,r=0,num=0; for(int i=1;i<=m;i++) { int tot=calc(q[i].r-q[i].l+1); while(l<q[i].l)num=num-calc(cnt[a[l]])+calc(--cnt[a[l]]),++l; while(l>q[i].l)--l,num=num-calc(cnt[a[l]])+calc(++cnt[a[l]]); while(r<q[i].r)++r,num=num-calc(cnt[a[r]])+calc(++cnt[a[r]]); while(r>q[i].r)num=num-calc(cnt[a[r]])+calc(--cnt[a[r]]),--r; int d=gcd(num,tot); ans[q[i].id]=make_pair(num/d,tot/d); } for(int i=1;i<=m;i++) cout<<ans[i].first<<'/'<<ans[i].second<<'\n'; return 0;}
阅读全文