bzoj2038 [2009国家集训队]小Z的袜子(hose) (莫队裸题)

来源:互联网 发布:java jar 打包依赖jar 编辑:程序博客网 时间:2024/06/11 05:10

bzoj2038 [2009国家集训队]小Z的袜子(hose)

原题地址:http://www.lydsy.com/JudgeOnline/problem.php?id=2038

题意:
小Z把N只袜子从1到N编号,每只袜子有颜色C,然后从编号L到R中任意抽取两只袜子,你的任务便是告诉小Z,他有多大的概率抽到两只颜色相同的袜子。当然,小Z希望这个概率尽量高,所以他可能会询问M个(L,R)以方便自己选择。

数据范围
N,M ≤ 50000,1 ≤ L < R ≤ N,Ci ≤ N。

题解:
(我的第一道莫队)
莫队裸题。
要开long long。
初始化如果l,r都设成0,要注意cnt[0]设为1,或者l=1,r=0。

代码:

#include<cstdio>#include<iostream>#include<algorithm>#include<cstring>#include<cmath>#define LL long longusing namespace std;const int N=50010;int n,m,s,col[N],cnt[N];LL sum,ans[N][2];int bel(int x){    return (x-1)/s+1;}struct node{    int L,R,note;    node(){}    node(int L,int R,int note) : L(L),R(R),note(note) {}}q[N];bool cmp(const node &A,const node &B){    if(bel(A.L)!=bel(B.L)) return A.L<B.L;    else return A.R<B.R;}void modify(int x,int val){    sum-=1LL*cnt[col[x]]*1LL*(cnt[col[x]]-1);    cnt[col[x]]+=val;    sum+=1LL*cnt[col[x]]*1LL*(cnt[col[x]]-1);}LL gcd(LL x,LL y){    return (y==0)?x:gcd(y,x%y);} void simp(LL x){    if(ans[x][0]==0) {ans[x][1]=1;return;}    LL g=gcd(ans[x][0],ans[x][1]);    ans[x][0]/=g; ans[x][1]/=g;    return;}int main(){    scanf("%d%d",&n,&m);    for(int i=1;i<=n;i++)    scanf("%d",&col[i]);    s=sqrt(n);    for(int i=1;i<=m;i++)    {        int L,R;        scanf("%d%d",&L,&R);        q[i]=node(L,R,i);    }    sort(q+1,q+m+1,cmp);    int lf=1; int rg=0;  //!!!    sum=0;    for(int i=1;i<=m;i++)    {        int L=q[i].L; int R=q[i].R; int note=q[i].note;        while(rg<R) modify(++rg,1);        while(rg>R) modify(rg--,-1);        while(lf>L) modify(--lf,1);        while(lf<L) modify(lf++,-1);        ans[note][0]=1LL*sum;        ans[note][1]=1LL*(R-L+1)*1LL*(R-L);    }    for(int i=1;i<=m;i++)    {        simp(i);        printf("%I64d/%I64d\n",ans[i][0],ans[i][1]);    }    return 0;}

引用下关于莫队的复杂度证明:

假设我们每k个点分一块。

如果当前询问与上一询问左端点处在同一块,那么左端点移动为O(k)。虽然右端点移动可能高达O(n),但是整一块询问的右端点移动距离之和也是O(n)(想一想,为什么)。因此平摊意义下,整块移动为O(k) × O(k) + O(n),一共有n / k块,时间复杂度为O(kn + n2 / k)。

总的移动次数为O(kn + n2 / k)。因此,当k = √n时,运行时间上界最优,为O( n1.5 )。

最后,因此根据每次insert和erase的时间复杂度,乘上O(1)或者O(logn)亦或O(n)不等,得到完整算法的时间复杂度。

阅读全文
0 0
原创粉丝点击