bzoj 2038 [2009国家集训队]小Z的袜子(hose)(莫队算法)
2016-04-01 09:07
531 查看
【题目链接】
http://www.lydsy.com/JudgeOnline/problem.php?id=2038
【题意】
给定一个有颜色的序列,回答若干个询问:区间内任选两个颜色相同的概率。
【思路】
设一个颜色在区间内的出现次数为cnt,则抽到这种颜色的概率为:
(cnt-1)*cnt/2 = 1+2+…+cnt-1
对于一个区间我们就可以使用一个cnt数组通过扫一遍得出答案。暴力的话,可以拿两个指针,每次移动指针,对数据进行插入与删除。
莫队算法就是在此基础上有序化了数据。将序列每sqrt(n)分成一块,根据查询的左端点所在块编号和右端点为第一二关键字排序。相邻的区间的重叠部分不重复计算,而是采用移动指针的方法,并通过合适的数据结构维护区间内的数据,支持在原来答案的基础上添加或删除数据即区间移动。
关于复杂度的分析:
一、i与i+1在同一块内,r单调递增,所以r是O(n)的。由于有n^0.5块,所以这一部分时间复杂度是n^1.5。
二、i与i+1跨越一块,r最多变化n,由于有n^0.5块,所以这一部分时间复杂度是n^1.5
三、i与i+1在同一块内时变化不超过n^0.5,跨越一块也不会超过2*n^0.5,不妨看作是n^0.5。由于有n个数,所以时间复杂度是n^1.5
于是就变成了O(n^1.5)了
from...不详
【代码】
http://www.lydsy.com/JudgeOnline/problem.php?id=2038
【题意】
给定一个有颜色的序列,回答若干个询问:区间内任选两个颜色相同的概率。
【思路】
设一个颜色在区间内的出现次数为cnt,则抽到这种颜色的概率为:
(cnt-1)*cnt/2 = 1+2+…+cnt-1
对于一个区间我们就可以使用一个cnt数组通过扫一遍得出答案。暴力的话,可以拿两个指针,每次移动指针,对数据进行插入与删除。
莫队算法就是在此基础上有序化了数据。将序列每sqrt(n)分成一块,根据查询的左端点所在块编号和右端点为第一二关键字排序。相邻的区间的重叠部分不重复计算,而是采用移动指针的方法,并通过合适的数据结构维护区间内的数据,支持在原来答案的基础上添加或删除数据即区间移动。
关于复杂度的分析:
一、i与i+1在同一块内,r单调递增,所以r是O(n)的。由于有n^0.5块,所以这一部分时间复杂度是n^1.5。
二、i与i+1跨越一块,r最多变化n,由于有n^0.5块,所以这一部分时间复杂度是n^1.5
三、i与i+1在同一块内时变化不超过n^0.5,跨越一块也不会超过2*n^0.5,不妨看作是n^0.5。由于有n个数,所以时间复杂度是n^1.5
于是就变成了O(n^1.5)了
from...不详
【代码】
#include<set> #include<cmath> #include<queue> #include<vector> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define trav(u,i) for(int i=front[u];i;i=e[i].nxt) #define FOR(a,b,c) for(int a=(b);a<=(c);a++) using namespace std; typedef long long ll; const int N = 5e4+10; ll read() { char c=getchar(); ll f=1,x=0; while(!isdigit(c)) { if(c=='-') f=-1; c=getchar(); } while(isdigit(c)) x=x*10+c-'0',c=getchar(); return x*f; } struct Node { int pos,l,r,id; bool operator < (const Node& rhs) const { return pos<rhs.pos||(pos==rhs.pos&&r<rhs.r); } }q ; ll gcd(ll a,ll b) { return b==0? a:gcd(b,a%b); } int n,m,c ,cnt ; pair<int,int> ans ; int main() { n=read(),m=read(); FOR(i,1,n) c[i]=read(); int B=sqrt(n); FOR(i,1,m) { q[i].l=read(); q[i].r=read(); q[i].pos=(q[i].l-1)/B+1; q[i].id=i; } sort(q+1,q+m+1); int l=1,r=0; ll now=0; FOR(i,1,m) { while(l>q[i].l) now+=cnt[c[--l]]++; while(l<q[i].l) now-=--cnt[c[l++]]; while(r<q[i].r) now+=cnt[c[++r]]++; while(r>q[i].r) now-=--cnt[c[r--]]; ll sum=(ll)(r-l+1)*(r-l)/2; ll g=gcd(sum,now); ans[q[i].id]=make_pair((int)now/g,(int)sum/g); } FOR(i,1,m) printf("%d/%d\n",ans[i].first,ans[i].second); return 0; }
相关文章推荐
- JDK与JRE及其在Eclipse中的使用
- 浮躁的时候看这儿
- 熬夜并不值得程序员炫耀
- nyoj847 S + T(贪心)
- 下拉滚动的实现
- js中字符串编码函数escape()、encodeURI()、encodeURIComponent()区别详解
- OC语言--NSFileManager& NSFileHandle
- OpenStack 架构 - 每天5分钟玩转 OpenStack(15)
- angularJs中上传图片/文件功能:ng-file-upload
- Android Studio引用fresco编译问题的处理
- java.util.concurrent.CountDownLatch
- Python中遇到"UnicodeDecodeError: ‘gbk’ codec can’t decode bytes in position 2-3: illegal multibyte sequ
- 万能的ctrl+shift+F(Element 'beans' cannot have character [children], because the type's content type is element-only.错误)
- 论指针与数组
- MFC->字符的编码方式
- 视频编码解码学习之二:编解码框架
- Sereja and Coat Rack(水)
- struts2中<s:select>标签的使用
- 浅析Motion Design
- 数组