Hellc
【题目描述】
作为一个生活散漫的人,小 Z 每天早上都要耗费很久从一堆五颜六色的袜子中找出一双来穿。终于有一天,小 Z 再也无法忍受这恼人的找袜子过程,于是他决定听天由命……
具体来说,小 Z 把这 $N$ 只袜子从 $1$ 到 $N$ 编号,然后从编号 $L$ 到 $R$ 的袜子中随机选取,尽管小 Z 并不在意两只袜子是不是完整的一双,甚至不在意两只袜子是否一左一右,他却很在意袜子的颜色,毕竟穿两只不同色的袜子会很尴尬。
你的任务便是告诉小 Z ,他有多大的概率抽到两只颜色相同的袜子。当然,小 Z 希望这个概率尽量高,所以他可能会询问多个 $(L, R)$ 以方便自己选择。
【题目链接】
BZOJ 2038 小 Z 的袜子 【国家集训队 2009】
【解题思路】
在区间 $[l, r]$ 内,设 $S$ 表示袜子的颜色集合,$f(x)$ 表示颜色 $x$ 出现的次数,根据古典概型:
$$
ans = frac {sum_{x in S} C(2, f(x))} {C(2, r - l + 1)}
$$
分母可以直接求出。
考虑到 $C(x, 2) = x(x - 1) = x^2 - x$,不妨将分子展开:
$$
begin{align*}
sum_{x in S} C(2, f(x))
& = sum_{x in S} (f^2(x) - f(x)) \
& = sum_{x in S} f^2(x) - sum_{x in S} f(x) \
& = sum_{x in S} f^2(x) - (r - l + 1)
end{align*}
$$
所以我们需要求的是每种颜色出现次数的平方和。
这可以用莫队算法解决,详见 莫队算法 - 学习笔记。
【AC代码】
#include <cstdio>
#include <algorithm>
#include <cmath>
typedef long long int64;
inline int64 sqr(int64 x){
return x * x;
}
inline int64 gcd(int64 a, int64 b){
int64 d = 1;
while(a && b){
while(~a & 1 && ~b & 1) a >>= 1, b >>= 1, d <<= 1;
while(~a & 1) a >>= 1;
while(~b & 1) b >>= 1;
if(a < b) std::swap(a, b);
a = a - b >> 1;
}
return std::max(a, b) * d;
}
inline void reduce(int64 &u, int64 &d){
int64 g = gcd(u, d);
u /= g, d /= g;
}
const int MAXN = 50000;
const int MAXM = 50000;
int n, m;
int a[MAXN];
int64 ansU[MAXM], ansD[MAXM];
int blockSize;
struct Query{
int l, r;
int id;
inline friend bool operator<(const Query &a, const Query &b){
if(a.l / blockSize != b.l / blockSize) return a.l / blockSize < b.l / blockSize;
else return a.r < b.r;
}
void calc(int64 sqrSum){
ansU[id] = sqrSum - (r - l + 1);
ansD[id] = (int64大专栏 Hellc>)(r - l) * (r - l + 1);
reduce(ansU[id], ansD[id]);
}
} querys[MAXM];
int l, r;
int f[MAXN + 1];
bool in[MAXN];
int64 currAns;
inline void flip(int pos){
in[pos] ^= 1;
currAns -= sqr(f[ a[pos] ]);
if(in[pos]){
f[ a[pos] ]++;
} else{
f[ a[pos] ]--;
}
currAns += sqr(f[ a[pos] ]);
}
inline void solve(){
blockSize = static_cast<int>(std::ceil(std::sqrt(n)) + 1e-6);
std::sort(querys, querys + m);
l = 0, r = 0, flip(0);
for(Query *q = querys; q != querys + m; q++){
while(l > q->l) flip(--l);
while(r < q->r) flip(++r);
while(l < q->l) flip(l++);
while(r > q->r) flip(r--);
q->calc(currAns);
}
}
int main(){
scanf("%d%d", &n, &m);
for(int i = 0; i < n; i++) scanf("%d", &a[i]);
for(int i = 0; i < m; i++){
Query *q = &querys[i];
scanf("%d%d", &q->l, &q->r), q->l--, q->r--;
q->id = i;
}
solve();
for(int i = 0; i < m; i++) printf("%lld/%lldn", ansU[i], ansD[i]);
return 0;
}
就是这样咯~
Hellc的更多相关文章
- JavaWeb 11_jsp九大内置对象
1. out: 输出对象,向客户端输出内容2. request: 请求对象;存储"客户端向服务端发送的请求信息" request对象的常见方法: String getParamet ...
随机推荐
- 《C程序设计(第四版)》小记
我看的这本书很经典,它是谭浩强写的,也就是广为流传的“C语言红皮书”.在网上看了很多帖子,生活中也问过一些朋友,大多数人是不认可这本书的.很多人都说这本书很烂,看不懂,然后去“追逐”国外的一些教材.其 ...
- Python - 文件和目录
# -*- coding: utf-8 -*- import os print(os.name) # 获取操作系统类型 # print(os.uname()) # 获取操作系统的详细信息,Win不支持 ...
- python XML ElementTree的增删改查
import xml.etree.ElementTree as ET """ ElementTree.write() 将构建的XML文档写入(更新)文件. Element ...
- 文件操作符|-e|-M|-s|-A|_|-r -w $filename|stat|localtime|&|>>|<<
TTY:终端是一种字符型设备,它有多种类型,通常使用tty 来简称各种类型的终端设备 #!/usr/bin/perl use strict; use warnings; print "exi ...
- 爬虫笔记(十四)——BeautifulSoup库
Beautifulsoup库: 该库是python语言写的,主要功能是将html.xml格式的数据对象解析成"标签树",并进行遍历和维护,即可以从网页抓取数据. 借鉴的html是妹 ...
- [tire+最短路]Bless You Autocorrect!
[tire+最短路]Bless You Autocorrect! Typing on phones can be tedious. It is easy to make typing mistakes ...
- 《VSTO开发中级教程》刘永富 著 清华大学出版社 在线购买
现在可以和作者 刘永富 通过“二手书直卖”这个APP直接买书. 二手书直卖 的下载方法: 方法一:加QQ群61840693,群共享中搜索“二手书直卖”,下载后打开即可. 方法二:从本帖下载:二手书直卖 ...
- 二十、linux文件系统讲解
1.分区和文件系统的关系: 为什么需要格式化呢?这是因为分区文件系统在没有格式化前,操作系统是无法识别系统分区的格式的,就没办法组织文件目录属性和权限等内容,把分区格式化成操作系统支持的某个文件系统后 ...
- 系统学习Javaweb9----BootStrap1
学习内容: 1.BootStrap的简述 2.BootStrap环境搭建 3.BootStrap环境搭建-基本模板创建 4.BootStrap环境搭建-基本模板讲解 5.BootStrap布局容器 6 ...
- 代码审计中的SQL注入
0x00 背景 SQL注入是一种常见Web漏洞,所谓SQL注入,就是通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令.本文以代码审计的形式研 ...