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

 

题目传送门

 1 /*
 2     莫队算法:求出[l, r]上取出两只相同袜子的个数。
 3         莫队算法是离线处理一类区间不修改查询类问题的算法。如果你知道了[L,R]的答案,可以在O(1)的时间下得到
 4         [L,R-1]和[L,R+1]和[L-1,R]和[L+1,R],4个while是精华!
 5         对于莫队算法我感觉就是暴力。只是预先知道了所有的询问。可以合理的组织计算每个询问的顺序以此来降低复杂度。
 6     详细解释:http://blog.csdn.net/bossup/article/details/39236275
 7 */
 8 #include <cstdio>
 9 #include <cstring>
10 #include <algorithm>
11 #include <cmath>
12 using namespace std;
13 
14 typedef long long ll;
15 const int MAXN = 5e4 + 10;
16 const int INF = 0x3f3f3f3f;
17 struct Data
18 {
19     int b, l, r, id;
20     ll x, y;
21     Data () {}
22     Data (int b, ll l, ll r, int id) : b (b), l (l), r (r), id (id) {};
23 }data[MAXN];
24 int cnt[MAXN];
25 int a[MAXN];
26 int n, m;
27 ll ans;
28 
29 bool cmp_pre(Data x, Data y)
30 {
31     if (x.b == y.b)    return x.r < y.r;
32     return x.b < y.b;
33 }
34 
35 bool cmp_id(Data x, Data y)    {return x.id < y.id;}
36 
37 ll cal(int v)    {return (ll) v * v;}
38 
39 void updata(int v, int add)
40 {
41     ans -= cal (cnt[v]);
42     cnt[v] += add;
43     ans += cal (cnt[v]);
44 }
45 
46 ll GCD(ll a, ll b)    {return b == 0 ? a : GCD (b, a % b);}
47 
48 void Modui(void)
49 {
50     sort (data+1, data+1+m, cmp_pre);
51     memset (cnt, 0, sizeof (cnt));
52 
53     int l = 1, r = 0;    ans = 0;
54     for (int i=1; i<=m; ++i)
55     {
56         while (data[i].l < l)    updata (a[--l], 1);
57         while (data[i].l > l)    updata (a[l], -1), l++;
58         while (data[i].r > r)    updata (a[++r], 1);
59         while (data[i].r < r)    updata (a[r], -1), r--;
60 
61         if (data[i].l == data[i].r)
62         {
63             data[i].x = 0;    data[i].y = 1;
64             continue;
65         }
66         data[i].x = ans - (data[i].r - data[i].l + 1);
67         data[i].y = (ll) (data[i].r - data[i].l + 1) * (data[i].r - data[i].l);
68         ll k = GCD (data[i].x, data[i].y);
69         data[i].x /= k;    data[i].y /= k;
70     }
71 
72     sort (data+1, data+1+m, cmp_id);
73     for (int i=1; i<=m; ++i)
74     {
75         printf ("%lld/%lld\n", data[i].x, data[i].y);
76     }
77 }
78 
79 int main(void)        //BOJ 2038 [2009国家集训队]小Z的袜子(hose)
80 {
81     // freopen ("BZOJ_2038.in", "r", stdin);
82 
83     while (scanf ("%d%d", &n, &m) == 2)
84     {
85         for (int i=1; i<=n; ++i)    scanf ("%d", &a[i]);
86 
87         int block = (int) sqrt (n * 1.0);
88         for (int i=1; i<=m; ++i)
89         {
90             int l, r;
91             scanf ("%d%d", &l, &r);
92             data[i] = Data (l / block, l, r, i);
93         }
94 
95         Modui ();
96     }
97 
98     return 0;
99 }

 

转载于:https://www.cnblogs.com/Running-Time/p/4644747.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值