首页 > 代码库 > [BZOJ 2038][2009国家集训队]小Z的袜子(hose)(莫队)
[BZOJ 2038][2009国家集训队]小Z的袜子(hose)(莫队)
Description
作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色的袜子中找出一双来穿。终于有一天,小Z再也无法忍受这恼人的找袜子过程,于是他决定听天由命……
具体来说,小Z把这N只袜子从1到N编号,然后从编号L到R(L 尽管小Z并不在意两只袜子是不是完整的一双,甚至不在意两只袜子是否一左一右,他却很在意袜子的颜色,毕竟穿两只不同色的袜子会很尴尬。
你的任务便是告诉小Z,他有多大的概率抽到两只颜色相同的袜子。当然,小Z希望这个概率尽量高,所以他可能会询问多个(L,R)以方便自己选择。
Solution
把询问按照左端点排序,块内按照右端点排序;
(l,r)的答案转移到(l+1,r)/(l-1,r)/(l,r+1)/(l,r-1)只需要O(1)的时间,所以总的时间复杂度是O(n^1.5)【黄学长blog有时间复杂度的分析 hzwer】
#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<cmath>#include<algorithm>#define MAXN 50005typedef long long LL;using namespace std;int n,m,unit,col[MAXN],num[MAXN];LL ans=0;struct Node{ int l,r,id; LL a,b;}q[MAXN];int Read(){ int x=0,f=1;char c=getchar(); while(c<‘0‘||c>‘9‘){ if(c==‘-‘)f=-1;c=getchar(); } while(c>=‘0‘&&c<=‘9‘){ x=x*10+c-‘0‘;c=getchar(); } return x*f;}bool cmp(Node A,Node B){ if(A.l/unit!=B.l/unit) return A.l/unit<B.l/unit; return A.r<B.r;}bool cmp_id(Node A,Node B){ return A.id<B.id;}LL gcd(LL a,LL b){ if(!b)return a; return gcd(b,a%b);}void update(int x,int add){ ans-=num[col[x]]*(num[col[x]]-1); num[col[x]]+=add; ans+=num[col[x]]*(num[col[x]]-1);}void work(){ int L=1,R=0; for(int i=0;i<m;i++) { while(q[i].l<L)update(L-1,1),L--; while(q[i].l>L)update(L,-1),L++; while(q[i].r<R)update(R,-1),R--; while(q[i].r>R)update(R+1,1),R++; if(q[i].l==q[i].r){q[i].a=0,q[i].b=1;continue;} q[i].a=ans; q[i].b=(LL)(R-L+1)*(R-L); LL k=gcd(q[i].a,q[i].b); q[i].a/=k,q[i].b/=k; }}int main(){ n=Read();m=Read(); unit=sqrt(n); for(int i=0;i<n;i++) col[i]=Read(); for(int i=0;i<m;i++) { q[i].l=Read()-1; q[i].r=Read()-1; q[i].id=i; } sort(q,q+m,cmp); work(); sort(q,q+m,cmp_id); for(int i=0;i<m;i++) { printf("%lld/%lld\n",q[i].a,q[i].b); } return 0;}
[BZOJ 2038][2009国家集训队]小Z的袜子(hose)(莫队)
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。