zoukankan      html  css  js  c++  java
  • 莫队算法

    原理

    1、离线操作。

    2、划分成若干块,将区间先按块排序,块内按区间右边界排序。块大小一般为sqrt(n)。

    3、按照排序后的区间进行操作,不断进行区间转移,更新答案。

    题目

    1、小Z的袜子(hose) HYSBZ - 2038

      题意:有n只袜子,求区间内颜色相同的两只袜子的概率。

      思路:对于区间[l,r],其概率为sum(cnt[i]*(cnt[i-1])|i∈val[l,..,r])/[(r-l+1)*(r-l)]。按照莫队的思想更新分子即可。

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<algorithm>
     4 #include<cmath>
     5 using namespace std;
     6 const int maxn = 5e5 + 10;
     7 const int maxm = 5e5 + 10;
     8 int n, m;
     9 int unit_len;
    10 int be[maxn];//记录下标L属于哪一个分块
    11 int val[maxn];
    12 int cnt[maxn];
    13 long long  ans;
    14 long long ansa[maxn],ansb[maxn]; //答案a / b
    15 struct node
    16 {
    17     int l, r,id;//区间[l,r]、输入顺序
    18     friend bool operator<(const node&n1, const node&n2)
    19     {
    20         if (be[n1.l] == be[n2.l]) return n1.r < n2.r;
    21         else return n1.l < n2.l;
    22     }
    23 }qs[maxm];
    24 long long GCD(long long a, long long b)
    25 {
    26     if (a < b) swap(a, b);
    27     while (b)
    28     {
    29         long long tmp = a % b;
    30         a = b;
    31         b = tmp;
    32     }
    33     return a;
    34 }
    35 long long cal(int x)
    36 {
    37     return 1ll * x*(x - 1);
    38 }
    39 void update(int pos, int v)
    40 {
    41     ans -= cal(cnt[val[pos]]);
    42     cnt[val[pos]] += v;
    43     ans += cal(cnt[val[pos]]);
    44 }
    45 void solve()
    46 {
    47     int l = 1, r = 0;
    48     ans = 0;
    49     for (int i = 1; i <= m; i++)
    50     {
    51         int id = qs[i].id;
    52         while (r < qs[i].r) update(r + 1, 1), r++;
    53         while (r > qs[i].r) update(r, -1),r--;
    54         while (l < qs[i].l) update(l, -1), l++;
    55         while (l > qs[i].l) update(l - 1, 1), l--;
    56         if (ans == 0) ansa[id] = 0, ansb[id] = 1;
    57         else
    58         {
    59             ansb[id]= cal(qs[i].r - qs[i].l + 1);
    60             ansa[id]= ans;
    61             long long gcd = GCD(ansa[id],ansb[id]);
    62             ansa[id]/= gcd;
    63             ansb[id] /= gcd;
    64         }
    65     }
    66 }
    67 int main()
    68 {
    69     while (~scanf("%d%d", &n, &m))
    70     {
    71         unit_len = sqrt(n);
    72         for (int i = 1; i <= n; i++) scanf("%d", &val[i]);
    73         for (int i = 1; i <= n; i++) be[i] = i / unit_len + 1;
    74         for (int i = 1; i <= m; i++) scanf("%d%d", &qs[i].l, &qs[i].r),qs[i].id=i;
    75         sort(qs + 1, qs + 1 + m);
    76         solve();
    77         for (int i = 1; i <= m; i++)
    78         {
    79             printf("%lld/%lld
    ", ansa[i], ansb[i]);
    80         }
    81     }
    82 
    83 
    84     return 0;
    85 }
    View Code

     2、Sona NBUT - 1457

      题意:求区间内,每种数值的三次方的和。

      思路:因为数值很大,需要离散化,接下来套莫队算法即可。注意输出long long用%64d。

     1 #include<iostream>
     2 #include<algorithm>
     3 #include<vector>
     4 #include<cstdio>
     5 #include<cmath>
     6 using namespace std;
     7 const int maxn = 1e5 + 10;
     8 int val[maxn];
     9 int nid[maxn];
    10 int be[maxn];
    11 int unit_len;
    12 int n, q,sz;
    13 vector<int>all;
    14 int cnt[maxn];
    15 long long tans;
    16 long long cal_cube(int x)
    17 {
    18     return 1ll * x*x*x;
    19 }
    20 struct op
    21 {
    22     int l, r,id;
    23     friend bool operator<(const op&o1, const op&o2)
    24     {
    25         if (be[o1.l] == be[o2.l]) return o1.r < o2.r;
    26         else return o1.l < o2.l;
    27     }
    28 }qs[maxn];
    29 long long ans[maxn];
    30 void update(int pos, int v)
    31 {
    32     tans -= cal_cube(cnt[pos]);
    33     cnt[pos] += v;
    34     tans += cal_cube(cnt[pos]);
    35 }
    36 void solve()
    37 {
    38     tans = 0;
    39     int l = 1, r = 0;
    40     for (int i = 1; i <= q; i++)
    41     {
    42         while (r < qs[i].r) update(nid[r + 1], 1), r++;
    43         while (l > qs[i].l) update(nid[l - 1], 1), l--;
    44 
    45         while (r > qs[i].r) update(nid[r], -1), r--;
    46         while (l < qs[i].l) update(nid[l], -1), l++;
    47         ans[qs[i].id] = tans;
    48     }
    49 }
    50 int main()
    51 {
    52     while (~scanf("%d", &n))
    53     {
    54         all.clear();
    55         for (int i = 1; i <= n; i++) scanf("%d", &val[i]),all.push_back(val[i]);
    56         sort(all.begin(), all.end());
    57         all.erase(unique(all.begin(), all.end()), all.end());
    58         sz = all.size();
    59         for (int i = 1; i <= n; i++) nid[i] = lower_bound(all.begin(), all.end(), val[i]) - all.begin() + 1;
    60         unit_len = (int)sqrt(1.0*n);
    61         for (int i = 1; i <= n; i++) be[i] = i / unit_len + 1,cnt[i]=0;
    62         scanf("%d", &q);
    63         for (int i = 1; i <= q; i++)
    64         {
    65             scanf("%d%d", &qs[i].l, &qs[i].r);
    66             qs[i].id = i;
    67         }
    68         sort(qs + 1, qs + 1 + q);
    69         solve();
    70         for (int i = 1; i <= q; i++) printf("%lld
    ", ans[i]);
    71     }
    72 
    73 
    74     return 0;
    75 }
    View Code

    3、Little Elephant and Array CodeForces-220B

      题意:给出一个数组,每次询问一个区间内出现次数恰好等于该数自身这样的数的个数。

      思路:莫队算法。注意,值大于1e5的都可以不用考虑,因为区间最大为1e5。

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<algorithm>
     4 #include<cmath>
     5 using namespace std;
     6 const int maxn = 1e5 + 10;
     7 const int maxm = 1e5 + 10;
     8 int n, m;
     9 int unit_len;
    10 int be[maxn]; //记录下标L属于哪一个分块
    11 int val[maxn];
    12 int cnt[maxn];
    13 long long ans;
    14 long long ansq[maxn]; //答案
    15 struct node
    16 {
    17     int l, r, id; //区间[l,r]、输入顺序
    18     friend bool operator<(const node&n1, const node&n2)
    19     {
    20         if (be[n1.l] == be[n2.l])
    21             return n1.r < n2.r;
    22         else
    23             return n1.l < n2.l;
    24     }
    25 } qs[maxm];
    26 
    27 long long cal(int cnt_x, int x)
    28 {
    29     if (cnt_x == x)
    30         return 1;
    31     else
    32         return 0;
    33 }
    34 void update(int pos, int v)
    35 {
    36     if (val[pos] >= maxn)
    37         return;
    38     ans -= cal(cnt[val[pos]], val[pos]);
    39     cnt[val[pos]] += v;
    40     ans += cal(cnt[val[pos]], val[pos]);
    41 }
    42 void solve()
    43 {
    44     int l = 1, r = 0;
    45     ans = 0;
    46     for (int i = 1; i <= m; i++)
    47     {
    48         int id = qs[i].id;
    49         while (r < qs[i].r)
    50             update(r + 1, 1), r++;
    51         while (r > qs[i].r)
    52             update(r, -1), r--;
    53         while (l < qs[i].l)
    54             update(l, -1), l++;
    55         while (l > qs[i].l)
    56             update(l - 1, 1), l--;
    57         ansq[id] = ans;
    58     }
    59 }
    60 int main()
    61 {
    62     scanf("%d%d", &n, &m);
    63     unit_len = sqrt(n);
    64     for (int i = 1; i <= n; i++)
    65         scanf("%d", &val[i]);
    66     for (int i = 1; i <= n; i++)
    67         be[i] = i / unit_len + 1;
    68     for (int i = 1; i <= m; i++)
    69         scanf("%d%d", &qs[i].l, &qs[i].r), qs[i].id = i;
    70     sort(qs + 1, qs + 1 + m);
    71     solve();
    72     for (int i = 1; i <= m; i++)
    73     {
    74         printf("%lld
    ", ansq[i]);
    75     }
    76     return 0;
    77 }
    View Code
  • 相关阅读:
    自定义控件-控件关联
    DELPHI INSERT INTO 语句的语法错误 解决方法
    Delphi控件开发
    Delphi控件复合控件
    vcl学习备忘网址
    Delphi单元文件Unit详解
    aowner , nil 和 self 的区别
    Delphi 自定义事件的例子
    PHP中Heredoc
    What is HTTP_USER_AGENT?
  • 原文地址:https://www.cnblogs.com/ivan-count/p/9407943.html
Copyright © 2011-2022 走看看