BZOJ
来源:互联网 发布:网络网警电话是多少 编辑:程序博客网 时间:2024/05/22 21:42
题目链接: 2038: [2009国家集训队]小Z的袜子(hose)
题目大意
一个长度为n的序列, 每个点有一个颜色, 用col[i]表示, q次询问, 每次求出[L, R]区间中随机选两个点的颜色相同的概率
思路
对于[L, R], 设区间内各种颜色的数量为
所以, 我们需要做的是快速求出区间内所有颜色数量的平方和
因为无法用线段树一类的数据结构进行处理, 所以需要用到传说中的莫队算法(Mo’s Algorithm)
莫队算法
莫队算法可以高效处理这类对大量区间进行查询, 通过对所有查询的区间进行离线排序处理, 使排序能够根据上一次询问的答案快速求出下一次询问的答案, 使得整体复杂度大大下降
如果知道了区间[L, R]的情况, 我们可以快速(
莫队算法的核心就是如何得到最优的处理顺序
一种简单但是复杂度略高一点的方法:
对于整个区间[1, n], 我们先将其分成
代码
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;}
阅读全文
0 0
- [BZOJ ]
- BZOJ****-****
- BZOJ
- BZOJ
- BZOJ
- BZOJ
- BZOJ
- BZOJ
- BZOJ
- BZOJ
- BZOJ
- BZOJ
- bzoj
- bzoj
- BZOJ
- BZOJ
- bzoj
- BZOJ
- 神经网络之文本情感分析(一)
- Java tcp聊天
- codevs 3311 [NOI2014] 起床困难综合症 贪心
- go语言 首字符大小写区别
- 大众点评数据分析
- BZOJ
- 冒泡法排序和数组去重
- poj2524 Ubiquitous Religions
- Volume-Docker存储(三)
- python 高级函数
- 三个国内pip源
- Spring系列——MyBatis(XML版)
- Iplimage设置感兴趣区域(ROI)
- 内存条