码迷,mamicode.com
首页 > 编程语言 > 详细

莫队算法

时间:2018-08-02 16:56:08      阅读:203      评论:0      收藏:0      [点我收藏+]

标签:opera   void   names   莫队   +=   算法   更新   main   离线操作   

原理

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\n", ansa[i], ansb[i]);
80         }
81     }
82 
83 
84     return 0;
85 }
View Code

 

莫队算法

标签:opera   void   names   莫队   +=   算法   更新   main   离线操作   

原文地址:https://www.cnblogs.com/ivan-count/p/9407943.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!