zoukankan      html  css  js  c++  java
  • 莫队-小Z的袜子

     ----普通莫队


    首先
    清楚概率怎么求
    假设我们要求从区间l到r中拿出一对袜子的概率
    sum[i]为第i种袜子在l到r中的数量

    $$frac{sum_{i=l}^{r} {[sum[i] imes (sum[i]-1)]}}{ (r-l+1) imes {(r-l)}}qquad$$

    转化一下可以得到

    $$frac{sum_{i=l}^{r} {sum[i]^{2}}-(r-l+1)}{ (r-l+1) imes {(r-l)}}qquad$$

    普通莫队是一种离线算法 并且充分利用上一个得到的答案来求得当前询问的答案


    怎么由上一个答案来得到当前的答案呢?


    $$ans=sum_{i=l}^{r} {sum[i]^{2}}$$

    即分母的一部分(减去(r-l+1)即可得到分母)

    现在要求[l+1,r]这个区间的答案
    若第l只袜子的编号为x 则只有sum[x]减少了1
    更新ans的操作如下:
    ans-=sum[x]*sum[x];
    sum[x]-=1;
    ans+=sum[x]*sum[x]
    即:减去从前对答案的贡献 加上现在的贡献
    求[l-1,r],[l,r-1],[l,r+1]的做法类比可得
    整理一下可以得到change函数

    //x为新增加或减少的点
    //若为新增加的点 如l指针左移和r指针右移 则w=1
    //反之 w=-1
    /*例子:求[l-1,r] change(l,-1)
           求[l,r+1] change(r+1,1) ……*/
    change(int x,int w)
    {
        ans-=sum[x]*sum[x];sum[x]+=w;ans+=sum[x]*sum[x];
    }

     

    为了使l和r指针尽可能少的移动(优化时间)
    我们需要给所有的问题的l和r排序

    构造cmp函数
    要用分块


    将整个长度为n的序列分为sqrt(n)块
    cmp为:若l与r在同一块中 则按照l从小到大排序
          否则 按照r从小到大排序
    这样l指针每次最多跳2*(n/sqrt(n))次
    最后求gcd 即可
    还要记得l==r的特判


    一种优秀的gcd求法

    //普通gcd
    int gcd(int x,int y)
    {
      return y==0?x:gcd(y,x%y);
    }


    其实可以看成是把x赋值为x%y 再调换x,y的位置 求gcd(x,y)
    假设我们要调换a,b的值

    //普通做法:
    int tmp;tmp=a;a=b;b=tmp;
    
    //其实可以利用位运算  异或
    x^=y;y^=x;x^=y;
    
    /*  第一步:x=x^y
        第二步:y=y^(x^y) 由于y^y=0 所以 y=x
        第三步:x=(x^y)^x 同理可得 x=y
    */

    可以得到gcd函数

    ll gcd(ll a,ll b)
    {
      while(b^=a^=b^=a%=b);return a;
    }
    //从右至左运算

    分析over

    code
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #define ll long long
    #define yes(i,a,b) for(register int i=a;i<=b;i++)
    #define M 50010
    using namespace std;
    int n,m,tot,len;
    ll ans,f_ans[M][2],sum[M];
    int c[M],be[M];
    struct node {int l,r,id;} q[M];
    bool cmp(node x,node y)
    {
      if(be[x.l]==be[y.l]) return x.r<y.r;
      return x.l<y.l;
    }
    void change(int x,int w)
    {
      ans-=(ll)(sum[c[x]]*sum[c[x]]);sum[c[x]]+=w;ans+=(ll)(sum[c[x]]*sum[c[x]]);
    }
    ll gcd(ll a,ll b)
    {
      while(b^=a^=b^=a%=b);return a;
    }
    int main()
    {
      //freopen("1.in","r",stdin);
      //freopen("1.out","w",stdout);
      scanf("%d%d",&n,&m);
      len=sqrt(n);
      yes(i,1,n) scanf("%d",&c[i]),be[i]=i/len+1;
      yes(i,1,m) scanf("%d%d",&q[i].l,&q[i].r),q[i].id=i;
      sort(q+1,q+m+1,cmp);
      int l=1,r=0;
      yes(i,1,m)
        {
          while(l<q[i].l) change(l,-1),l++;
          while(l>q[i].l) change(l-1,1),l--;
          while(r<q[i].r) change(r+1,1),r++;
          while(r>q[i].r) change(r,-1),r--;
          ll ans1,ans2;
          ans1=ans-(ll)(q[i].r-q[i].l+1);ans2=(ll)(q[i].r-q[i].l+1)*(q[i].r-q[i].l);
          if(ans1==0) ans2=1;
          else
        {
          ll g=gcd(ans2,ans1);
          ans1/=g;ans2/=g;
        }
          f_ans[q[i].id][0]=ans1;f_ans[q[i].id][1]=ans2;
        }
      yes(i,1,m) printf("%lld/%lld
    ",f_ans[i][0],f_ans[i][1]);
      return 0;
    }
    光伴随的阴影
  • 相关阅读:
    New version of VS2005 extensions for SharePoint 3.0
    QuickPart : 用户控件包装器 for SharePoint Server 2007
    随想
    发布 SharePoint Server 2007 Starter Page
    如何在SharePoint Server中整合其他应用系统?
    Office SharePoint Server 2007 中文180天评估版到货!
    RMS 1.0 SP2
    SharePoint Server 2007 Web内容管理中的几个关键概念
    如何为已存在的SharePoint站点启用SSL
    Some update information about Office 2007
  • 原文地址:https://www.cnblogs.com/forward777/p/10086599.html
Copyright © 2011-2022 走看看