zoukankan      html  css  js  c++  java
  • 【BZOJ2038】小Z的袜子(2009国家集训队)-莫队算法

    测试地址:小Z的袜子

    做法:设f(i)为颜色i在区间[l,r]内出现的次数,则区间[l,r]的答案为:ΣC(2,f(i))/C(2,r-l+1),面对这种东西线段树就无能为力了......怎么办呢?

    于是本人今天学习了传说中离线处理区间询问的无敌算法——莫队算法,感觉妙极!莫队算法的讲解见这里。这篇博客中也以这一题作为例题,讲得比较详细了,那我就来讲讲具体实现吧:因为答案的式子中大部分都可以直接通过l和r求出,所以我们只用维护一个ans=Σ(f(i))^2,在从(l,r)转移到(l,r+1)时,假设点r+1的颜色是c,那么ans就比原来多:(f(c)+1)^2-f(c)^2=2*f(c)+1。而从(l,r)转移到(l,r-1)时就略微不同,ans比原来多:(f(c)-1)^2-f(c)^2=-2*f(c)+1。于是可以发现,当我们转移的区间是扩大的时候,ans增加的就是2*f(c)+1,反之就是-2*f(c)+1,然后答案就按照上面那篇博客说的一样计算即可。化成最简分数其实就是分子和分母同除它们的gcd(这个还不懂的话......听天由命吧)。

    以下是本人代码:

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #include <cmath>
    using namespace std;
    int n,m,c[50010],pos[50010],f[50010]={0};
    struct query
    {
      long long a,b;
      int l,r,id;
    }q[50010];
    
    bool cmp1(query a,query b)
    {
      return pos[a.l]<pos[b.l]||(pos[a.l]==pos[b.l]&&a.r<b.r);
    }
    
    bool cmp2(query a,query b)
    {
      return a.id<b.id;
    }
    
    void init()
    {
      scanf("%d%d",&n,&m);
      int block=(int)sqrt((double)n+0.5);
      for(int i=1;i<=n;i++)
      {
        scanf("%d",&c[i]);
        pos[i]=(i-1)/block+1;
      }
      for(int i=1;i<=m;i++)
      {
        scanf("%d%d",&q[i].l,&q[i].r);
    	q[i].id=i;
      }
      sort(q+1,q+m+1,cmp1);
    }
    
    void transfer(long long p,long long &ans,long long add)
    {
      ans=ans+2*add*f[c[p]]+1;
      f[c[p]]+=add;
    }
    
    long long gcd(long long a,long long b)
    {
      return (b==0)?a:gcd(b,a%b);
    }
    
    void solve()
    {
      long long ans=0,l=1,r=0;
      for(int i=1;i<=m;i++)
      {
        if (r<q[i].r) while(r<q[i].r) r++,transfer(r,ans,1);
    	if (q[i].l<l) while(l>q[i].l) l--,transfer(l,ans,1);
    	if (r>q[i].r) while(r>q[i].r) transfer(r,ans,-1),r--;
    	if (q[i].l>l) while(l<q[i].l) transfer(l,ans,-1),l++;
    	if (l==r) {q[i].a=0,q[i].b=1;continue;}
    	q[i].a=ans-(r-l+1);q[i].b=(r-l+1)*(r-l);
        long long g=gcd(q[i].a,q[i].b);
    	q[i].a/=g,q[i].b/=g;
      }
      sort(q+1,q+m+1,cmp2);
      for(int i=1;i<=m;i++)
        printf("%lld/%lld
    ",q[i].a,q[i].b);
    }
    
    int main()
    {
      init();
      solve();
      
      return 0;
    }
    


  • 相关阅读:
    topcoder srm 445 div1
    topcoder srm 440 div1
    topcoder srm 435 div1
    topcoder srm 430 div1
    topcoder srm 400 div1
    topcoder srm 380 div1
    topcoder srm 370 div1
    topcoder srm 425 div1
    WKWebView强大的新特性
    Runtime那些事
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793719.html
Copyright © 2011-2022 走看看