【BZOJ 2038】小Z的袜子 (莫队算法)
2017-08-17 22:11
281 查看
传送门
BZOJ 2038 小Z的袜子I think
题意:给出长度为n的区间与若干形如[l,r]的区间,询问在[l,r]内两个不同位置取到两个相同的数的概率。算法:莫队
思想:将组合数求概率的式子化简一下:
P(抽到相同颜色)=∑coli=1C2f[i]C2r−l+1=∑coli=1C2f[i](r−l+1)∗(r−l)2
(col 表示区间内颜色总数 f[i]表示区间内颜色出现次数)
于是我们可以看伟大的黄学长题解
莫队算法
如果我们已知[l,r]的答案,能在O(1)时间得到[l+1,r]的答案以及[l,r-1]的答案,即可使用莫队算法。时间复杂度为O(n^1.5)。如果只能在logn的时间移动区间,则时间复杂度是O(n^1.5*log n)。
其实就是找一个数据结构支持插入、删除时维护当前答案。
这道题的话我们很容易用数组来实现,做到O(1)的从[l,r]转移到[l,r+1]与[l+1,r]。
那么莫队算法怎么做呢?以下都是在转移为O(1)的基础下讨论的时间复杂度。另外由于n与m同阶,就统一写n。
如果已知[l,r]的答案,要求[l’,r’]的答案,我们很容易通过|l – l’|+|r – r’|次转移内求得。
将n个数分成sqrt(n)块。
按区间排序,以左端点所在块内为第一关键字,右端点为第二关键字,进行排序,也就是以(pos [l],r)排序
然后按这个排序直接暴力,复杂度分析是这样的:
1、i与i+1在同一块内,r单调递增,所以r是O(n)的。由于有n^0.5块,所以这一部分时间复杂度是n^1.5。
2、i与i+1跨越一块,r最多变化n,由于有n^0.5块,所以这一部分时间复杂度是n^1.5
3、i与i+1在同一块内时l变化不超过n^0.5,跨越一块也不会超过n^0.5,忽略*2。由于有m次询问(和n同级),所以时间复杂度是n^1.5
于是就是O(n^1.5)了
最后最小公倍数约一下分子分母就可以输出答案了。
Code
#include<cmath> #include<cstdio> #include<algorithm> using namespace std; typedef long long LL; const int sm = 50000+10; LL Ans; int N,M,Blk; int S[sm],C[sm],pos[sm]; struct Que { int id,l,r; LL a,b; }A[sm]; LL Gcd(LL a,LL b) { return b == 0?a:Gcd(b,a%b); } LL ind(int x) { return 1ll*x*x; } void read(int &x) { char ch=getchar();x=0; while(ch>'9'||ch<'0') ch=getchar(); while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); } void Out(LL a) { if(a>9) Out(a/10); putchar('0'+a%10); } bool cmpa(Que x,Que y) { return (pos[x.l]!=pos[y.l])?pos[x.l]<pos[y.l]:x.r<y.r; } bool cmpb(Que x,Que y) { return x.id<y.id; } void Update(int p,int add) { Ans-=ind(S[C[p]]); S[C[p]]+=add; Ans+=ind(S[C[p]]); } void Solve() { int l=1,r=0;//注意l=1的细节 LL k; for(int i=1;i<=M;++i) { for(;r<A[i].r;++r) Update(r+1,1); for(;r>A[i].r;--r) Update(r,-1); for(;l<A[i].l;++l) Update(l,-1); for(;l>A[i].l;--l) Update(l-1,1); if(A[i].l==A[i].r) { A[i].a=0,A[i].b=1; continue; } A[i].a=Ans-(A[i].r-A[i].l+1); A[i].b=1ll*(A[i].r-A[i].l+1)*(A[i].r-A[i].l); k=Gcd(A[i].a,A[i].b); A[i].a/=k,A[i].b/=k; } } int main() { read(N),read(M); Blk=sqrt(N); for(int i=1;i<=N;++i) read(C[i]),pos[i]=(i-1)/Blk+1; for(int i=1;i<=M;++i) read(A[i].l),read(A[i].r),A[i].id=i; sort(A+1,A+M+1,cmpa); Solve(); sort(A+1,A+M+1,cmpb); for(int i=1;i<=M;++i) { Out(A[i].a),putchar('/'); Out(A[i].b),putchar(10); } return 0; }
相关文章推荐
- BZOJ 2038 [2009国家集训队]小Z的袜子(hose) (莫队算法)
- BZOJ 2038([2009国家集训队]小Z的袜子(hose)-莫队算法序列)
- bzoj 2038 A-小Z的袜子[hose] - 莫队算法
- BZOJ - 2038 小Z的袜子 莫队算法
- bzoj 2038: [2009国家集训队]小Z的袜子(hose) 【莫队算法】
- BZOJ 2038 2009国家集训队 小Z的袜子 莫队算法
- BZOJ 2038: [2009国家集训队]小Z的袜子(hose)(莫队算法)
- 莫队算法 BZOJ 2038 小Z的袜子
- BZOJ 2038 小Z的袜子(hose) 莫队算法
- BZOJ 2038 小Z的袜子 莫队算法(模板题)
- BZOJ 2038: [2009国家集训队]小Z的袜子(hose) [莫队算法]【学习笔记】
- bzoj 2038 小Z的袜子(hose)(莫队算法)
- [BZOJ]2038: [2009国家集训队]小Z的袜子(hose) 莫队算法
- BZOJ-2038 小Z的袜子(hose) (莫队算法)
- bzoj 2038: [2009国家集训队]小Z的袜子(hose)(莫队算法)
- bzoj 2038 [2009国家集训队]小Z的袜子(hose)(莫队算法)
- BZOJ_2038 小Z的袜子(莫队算法)
- bzoj 2038 [2009国家集训队]小Z的袜子(hose)(莫队算法)
- BZOJ 2038 小Z的袜子(hose) (莫队算法)
- bzoj 2038: [2009国家集训队]小Z的袜子(hose) 莫队算法