BZOJ - 2038: 小Z的袜子(hose) 莫队算法 模板

AI权益加码!Claude Code、Cursor等20+工具免费用! 购周边限时加赠Coding Plan Lite,畅享主流AI工具!学习进阶更高效! 阅读详情

题目链接: 2038: [2009国家集训队]小Z的袜子(hose)

题目大意

一个长度为n的序列, 每个点有一个颜色, 用col[i]表示, q次询问, 每次求出[L, R]区间中随机选两个点的颜色相同的概率

思路

对于[L, R], 设区间内各种颜色的数量为 a,b,c , 则答案为:

a(a1)2+b(b1)2+c(c1)2(RL+1)(RL)2

a2+b2+c2+(a+b+c+)(RL+1)(RL)

a2+b2+c2+(RL+1)(RL+1)(RL)

所以, 我们需要做的是快速求出区间内所有颜色数量的平方和
因为无法用线段树一类的数据结构进行处理, 所以需要用到传说中的莫队算法(Mo’s Algorithm)

莫队算法

莫队算法可以高效处理这类对大量区间进行查询, 通过对所有查询的区间进行离线排序处理, 使排序能够根据上一次询问的答案快速求出下一次询问的答案, 使得整体复杂度大大下降
如果知道了区间[L, R]的情况, 我们可以快速( O(1) )求出相邻区间([L-1, R], [L+1, R], [L, R-1], [L, R+1])的答案, 那么对于大量的询问, 我们按某个顺序一次处理询问, 就可以使得总体的复杂度降低到 O(nn)
莫队算法的核心就是如何得到最优的处理顺序
一种简单但是复杂度略高一点的方法:
对于整个区间[1, n], 我们先将其分成 n 个块, 给每个块依次编号, 然后, 对于每个询问区间[L, R], 先按L所在的块排序, 如果L在同一块, 再按照R的大小排序, 然后根据这个顺序离线处理所有询问, 效率可以达到 O(nn)

代码

Accepted 1472ms 3456kB C++

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cmath>

using namespace std;

const int maxn = 5e4 + 100;
typedef long long ll;

int n, m, block[maxn], col[maxn];
ll sum[maxn], ans;//sum[i]存储当前区间颜色i的数量, ans表示当前区间各个颜色数量和

ll gcd(ll a, ll b) { return b ? gcd(b, a % b) : a; }

struct Query
{
    int l, r, id;
    ll nume, deno;//答案分子分母
} querys[maxn];

bool cmp(const Query & x, const Query & y)
{
    if (block[x.l] == block[y.l]) return x.r < y.r;
    return x.l < y.l;
}
bool cmp_id(const Query & x, const Query & y)
{
    return x.id < y.id;
}

void update(int p, int add)//区间向相邻区间移动, 更新答案
{
    int c = col[p];
    ans -= sum[c] * sum[c];
    sum[c] += add;
    ans += sum[c] * sum[c];
}

int main()
{
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; ++i) scanf("%d", col + i);
    int block_size = (int)sqrt(n);
    for (int i = 1; i <= n; ++i) block[i] = (i - 1) / block_size + 1;
    for (int i = 1; i <= m; ++i)
    {
        scanf("%d%d", &querys[i].l, &querys[i].r);
        querys[i].id = i;
    }

    sort(querys + 1, querys + 1 + m, cmp);
    int l = 1, r = 0;//最初为一个空区间[1, 0], ans(颜色数量平方和) = 0
    for (int i = 1; i <= m; ++i)
    {
        //更新区间, 从上一个区间得到下一个区间的情况
        for (; r < querys[i].r; ++r) update(r + 1, 1);
        for (; r > querys[i].r; --r) update(r, -1);
        for (; l < querys[i].l; ++l) update(l, -1);
        for (; l > querys[i].l; --l) update(l - 1, 1);

        //计算答案并化简分数
        if (querys[i].l == querys[i].r)
        {
            querys[i].nume = 0;
            querys[i].deno = 1;
            continue;
        }

        ll len = querys[i].r - querys[i].l + 1;
        querys[i].nume = ans - len;
        querys[i].deno = len * (len - 1);
        ll t = gcd(querys[i].nume, querys[i].deno);
        querys[i].nume /= t;
        querys[i].deno /= t;
    }

    //输出答案
    sort(querys + 1, querys + 1 + m, cmp_id);
    for (int i = 1; i <= m; ++i) printf("%lld/%lld\n", querys[i].nume, querys[i].deno);

    return 0;
}
[BZOJ]2038 小Z的袜子 莫队算法 代码:#include<cstdio> #include<iostream> #include<cmath> #include<algorithm> #define ll long long using namespace std; const int N=50010; int n,m; int col[N],f[N],pos[N]; ll gcd(ll x,ll y) { return y 阅读详情

相关推荐

BZOJ2038莫队算法

THE FIRST 莫队算法。 /************************************************************** Problem: 2038 User: keyboarder_zsq Language: C++ Result: Accepted Time:1644 ms Memory:2988 ...

weixin_30537451的博客 148

bzoj2038(莫队算法

题目:给出一个数列,要求快速查询区间lr内相同数字的对数。 思路:对于每次询问暴力跑,但是我们注意到由于可以复用之前的结果,所以不同的计算顺序计算量可能不同,直观上来说,两个查询点的曼哈顿距离越短,需要计算的量就越小。于是我们可以找出一个最佳计算顺序,就是平面点阵的最短哈密顿回路。由于这是np的,所以可以用最小曼哈顿生成树代替。再简化一下,可以使用分快处理的方法得到比较快的速度。 这...

aduqw1129的博客 191

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

题面在这里莫队的经典题…… 对于已知区间[L,R],它的答案是: ∑C2c[i]的个数C2R−L+1\frac{\sum C_{c[i]的个数}^2}{C_{R-L+1}^2} 由于处理分数比较麻烦,所以我们只要维护分子即可 即:对于变化的c[i]个数(设为x),维护C2xC_x^2 减去原来的,加上后面的即可附上代码:#include<cstdio> #include<algorithm

linkfqy 1180

bzoj2038(小z的袜子——莫队)

莫队的模板题。莫队的注意点记在蓝书上了。   本题关键的是莫队的基本写法需要记清楚 #include #include #include #include using namespace std; typedef long long ll; const int N=60005; int n,m,c[N]; int pos[N]; ll ans,ml,mr,sum[N]; struct aa/

zhhx2001的博客 349

BZOJ 2038 小Z的袜子(hose) 莫队算法模板

题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=2038 题目大意: 作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色的袜子中找出一双来穿。终于有一天,小Z再也无法忍受这恼人的找袜子过程,于是他决定听天由命……具体来说,小Z把这N只袜子从1到N编号,然后从编号L到R(L尽管小Z并不在意两只袜子是不是完整的一双,甚至不...

weixin_34292959的博客 131

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

Description 作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色的袜子中找出一双来穿。终于有一天,小Z再也无法忍受这恼人的找袜子过程,于是他决定听天由命…… 具体来说,小Z把这N只袜子从1到N编号,然后从编号L到R(L 尽管小Z并不在意两只袜子是不是完整的一双,甚至不在意两只袜子是否一左一右,他却很在意袜子的颜色,毕竟穿两只不同色的袜子会很尴尬。 你的任务便是告诉小Z

ZAQ的博客 1378

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

2038: [2009国家集训队]小Z的袜子(hose) Time Limit: 20 Sec Memory Limit: 259 MB Submit: 19269 Solved: 8851 [Submit][Status][Discuss] Description 作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色的袜子中找出一双来穿。终于有一天,小Z再也无法忍受这恼人的找袜...

weixin_30387663的博客 127

莫队入门例题:2038: [2009国家集训队]小Z的袜子(hose)

题目大意: Description 作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色的袜子中找出一双来穿。终于有一天,小Z再也无法忍受这恼人的找袜子过程,于是他决定听天由命…… 具体来说,小Z把这N只袜子从1到N编号,然后从编号L到R(L尽管小Z并不在意两只袜子是不是完整的一双,甚至不在意两只袜子是否一左一右,他却很在意袜子的颜色,毕竟穿两只不同色的袜子会很尴尬。 你的任务便是告...

xizi_ghq的博客 262

BZOJ 2038 小Z的袜子(hose)

给出N个数,M个询问区间,对于每个询问你需要给出:区间内取出两个数相同的概率。

Asuna_acmer 611

BZOJ 2038: [2009国家集训队]小Z的袜子(hose)

分块

sdfzrlt的博客 330

BZOJ 2038 && hdu 6333

  2038: [2009国家集训队]小Z的袜子(hose) Time Limit: 20 Sec  Memory Limit: 259 MB Submit: 15491  Solved: 7029 [Submit][Status][Discuss] Description 作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色的袜子中找出一双来穿。终于有一天,小Z再也无法忍受这恼人...

oWuHen12的博客 439

BZOJ 2038 小Z的袜子(hose) 莫队算法

题目:http://www.lydsy.com/JudgeOnline/problem.php?id=2038题意:给出一个长为n的序列,m次查询,每次查询一个l,r问在l,r区间内任取两个数相同的概率是多少。公式化简的:(sigma(s(i)^2)-sigma(s(i))/(l-r+1)*(l-r);题目转化为求区间[l,r]内出现的所有数字的出现次数平方和,莫队算法模板题,注意公式分母会爆i...

~不可描述~ 223

[Bzoj2039]小Z的袜子莫队算法模板题)

2038: [2009国家集训队]小Z的袜子(hose) Time Limit:20 SecMemory Limit:259 MBSubmit:11866Solved:5318[Submit][Status][Discuss] Description 作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色的袜子中找出一双来穿。终于有一天,小Z...

weixin_30268921的博客 151

BZOJ 2038: [2009国家集训队]小Z的袜子(hose)莫队算法模版】

任意门:https://www.lydsy.com/JudgeOnline/problem.php?id=2038 题意概括: 有 N 只袜子(分别编号为1~N),有 M 次查询 (L, R)里面随机拿两只袜子,拿到相同颜色袜子的概率是多少。 解题思路: 莫队算法经典题,暴力找出区间内相同颜色的袜子的个数,排列组合最后得出结果。 入门题,当模版。 AC code: 1 #inclu...

Mod_13的博客 109

bzoj-2038-莫队

2038: [2009国家集训队]小Z的袜子(hose) Time Limit:20 SecMemory Limit:259 MBSubmit:15784Solved:7164[Submit][Status][Discuss] Description 作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色的袜子中找出一双来穿。终于有一天,小Z再也无法忍...

all00747的博客 188

[BZOJ 2038]小Z的袜子 莫队(Mo's Algorithm)模板

自己写了一种比较舒服的区间增减 如果当前已知区间的左端点小于询问区间的左端点,则需要将当前已知区间的左端点向右移。每次右移之前都需要先减去当前点对答案的影响。 如果当前已知区间的左端点大于询问区间的左端点,则需要将当前已知区间的左端点向左移。每次左移之后都需要再加上当前点对答案的影响。 右区间同理

Muruan 296

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

题目: bzoj 2038分析:莫队算法模版题。代码:#include <iostream> #include <cstdio> #include <algorithm> #include <cmath> #define LL long long const int maxn=50003;using namespace std;struct node{ int l,r,id; LL

liangzihao1的博客 200

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

题意给出n个数字m次询问,每次询问在区间[li,ri][li,ri][li,ri][li,ri]之间任选两个数字相等的概率是多少.(n,q<=50000)题解莫队模板题。 所谓莫队其实就是个高逼格的暴力,想法特别简单,不赘述了。 对于这题,我们设sum[i]表示区间[L,R]中i出现次数,则概率为: ∑C(sum[k],2)C(R−L+1,2) \frac{\sum C(sum[k],2)}{

Lynstery's blog 521
上一篇: Codeforces Round #442 (Div. 2) 877 E. Danil and a Part-time Job DFS序 线段树
下一篇: Codeforces Round #442 (Div. 2) 877 F - Ann and Books 莫队算法 离散化
litmxs
博客等级 码龄10年 11粉丝 132原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值