• BZOJ2038 [2009国家集训队]小Z的袜子(hose)(莫队算法)


    神奇的莫队算法,用来解决可离线无修改的区间查询问题:

    • 首先对原序列进行分块,√n块每块√n个;
    • 然后对所有查询的区间[l,r]进行排序,首先按l所在的块序号升序排序,如果一样就按r升序排序;
    • 最后就按顺序一个一个求出各个查询的结果:知道[l,r]的答案,并且在此基础上能在比较快地在O(x)得到相邻区间[l+1,r]、[l-1,r]、[l,r-1]、[l,r+1]的答案,那样就能从[l,r]的基础上对lr加加减减得到任意一个区间[l',r']的答案。

    看似暴力,但这样做的时间复杂度是O(x*n*√n) !因为:

    • l是按其所在块序号排列,同一块里面一次最多√n次++l或--l到达目标;一块最多大概√n次加加减减;总共√n块;所以l改变的次数顶多也就√n*√n*√n。
    • r在同一块是升序的,所以同一块最多n次++r;下一块时r假设在上一块到达最远,那最多n次--r回到目标;总共√n块;所以r改变次数顶多也就(n+n)*√n。
    • 而每次加加减减转移新答案的代价是x,所以时间复杂度是O(x*n*√n) !

    这一题,设每个区间[l,r]各个颜色的袜子数分别为$a,b,c,d,dots$,每个区间[l,r]的答案就是$(C_a^2+C_b^2+C_c^2+C_d^2+cdots)/C_{r-l+1}^2$,展开化简得:

    $$(a^2+b^2+c^2+d^2+cdots-a-b-c-d-cdots)/((r-l+1)*(r-l+1-1))$$

    $$(a^2+b^2+c^2+d^2+cdots-(r-l+1))/((r-l+1)*(r-l))$$

    其中$(a^2+b^2+c^2+d^2+cdots)$便可作为莫队算法处理的区间答案,开个数组记录abcd...的个数可以在O(1)转移到相邻区间。

    另外特判区间l=r的情况。。

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<cmath>
     4 #include<algorithm>
     5 using namespace std;
     6 #define MAXN 55555
     7 
     8 int block;
     9 struct Query{
    10     int i,l,r;
    11     bool operator<(const Query &q)const{
    12         if(l/block==q.l/block) return r<q.r;
    13         return l/block<q.l/block;
    14     }
    15 }query[MAXN];
    16 
    17 long long gcd(long long a,long long b){
    18     if(b==0) return a;
    19     return gcd(b,a%b);
    20 }
    21 
    22 int seq[MAXN];
    23 long long cnt[MAXN],ansx[MAXN],ansy[MAXN];
    24 void insert(long long &res,int a){
    25     res-=cnt[a]*cnt[a];
    26     ++cnt[a];
    27     res+=cnt[a]*cnt[a];
    28 }
    29 void remove(long long &res,int a){
    30     res-=cnt[a]*cnt[a];
    31     --cnt[a];
    32     res+=cnt[a]*cnt[a];
    33 }
    34 int main(){
    35     int n,m;
    36     scanf("%d%d",&n,&m);
    37     block=sqrt(n);
    38     for(int i=1; i<=n; ++i) scanf("%d",seq+i);
    39     for(int i=0; i<m; ++i){
    40         query[i].i=i;
    41         scanf("%d%d",&query[i].l,&query[i].r);
    42     }
    43     sort(query,query+m);
    44     int l=1,r=1;
    45     ++cnt[seq[1]];
    46     long long res=1;
    47     for(int i=0; i<m; ++i){
    48         if(query[i].l==query[i].r){
    49             ansx[query[i].i]=0; ansy[query[i].i]=1;
    50             continue;
    51         }
    52         while(l<query[i].l){
    53             remove(res,seq[l]);
    54             ++l;
    55         }
    56         while(l>query[i].l){
    57             --l;
    58             insert(res,seq[l]);
    59         }
    60         while(r<query[i].r){
    61             ++r;
    62             insert(res,seq[r]);
    63         }
    64         while(r>query[i].r){
    65             remove(res,seq[r]);
    66             --r;
    67         }
    68         long long a=res-(query[i].r-query[i].l+1),b=(query[i].r-query[i].l+1LL)*(query[i].r-query[i].l),c=gcd(b,a);
    69         ansx[query[i].i]=a/c; ansy[query[i].i]=b/c;
    70     }
    71     for(int i=0; i<m; ++i) printf("%lld/%lld
    ",ansx[i],ansy[i]);
    72     return 0;
    73 }
  • 相关阅读:
    如何面试前端工程师!
    CSS实现背景透明,文字不透明(各浏览器兼容)
    IE6中伪类:hover的使用及BUG
    jQuery UIdraggable参数学习
    PHP与正则表达式 2 :一些修饰符与preg_match_all
    通过apktool获取apk package name(包名)以及activity name
    jquery.ui.draggable中文文档
    无法加载php_curl.dll解决办法
    ubuntu命令查询版本和内核版本
    linux zip, unzip命令详解[ubuntu]
  • 原文地址:https://www.cnblogs.com/WABoss/p/5226684.html
Copyright © 2020-2023  润新知