【题目描述】

作为一个生活散漫的人,小 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的更多相关文章

  1. JavaWeb 11_jsp九大内置对象

    1. out: 输出对象,向客户端输出内容2. request: 请求对象;存储"客户端向服务端发送的请求信息" request对象的常见方法: String getParamet ...

随机推荐

  1. typescript 使用的几种情况

    接口的创建 可以使用 type 和 interface 来创建类型 type 特有的优点: 声明基本类型别名,联合类型,元组等类型 type S = string; type IFoo = IBar ...

  2. Git-GitHub-GitLab三者之间的联系及区别

    在讲区别以及联系之前先简要的介绍一下,这三者都是什么(本篇文章适合刚入门的新手,大佬请出门左转) 1.什么是 Git? Git 是一个版本控制系统. 版本控制是一种用于记录一个或多个文件内容变化,方便 ...

  3. 关于前端jquery的总结

    简介 jQuery是一个JavaScript库,特性丰富,包含若干对象和很多函数,可以代替传统DOM编程的操作方式和操作风格,通过对DOM  API.DOM事件的封装,提供了一套全新的API,这套全新 ...

  4. Java统计内存

    在目标代码前放置 Runtime r = Runtime.getRuntime(); r.gc(); long startMem = r.freeMemory(); // 开始时的剩余内存 目标代码执 ...

  5. 在win10下安装ubuntu双系统总结

    在打算装双系统前两天,我事先在网上买了一个16G大小的U盘,用来坐启动盘.后来发现其实有4G大小就远远足够的,16G的太浪费了,忘后来人吸取教训.呜呜呜.....下面给大家讲讲我的安装步骤: 参考文章 ...

  6. OpenCV、EmguCV函数注解

  7. bootstrap实现多选项及回显

    1.前端 <link rel="stylesheet" href="${ctxStatic}/js/bootstrap-select-1.12.2/dist/css ...

  8. 吴裕雄--天生自然python学习笔记:Python3 日期和时间

    Python 程序能用很多方式处理日期和时间,转换日期格式是一个常见的功能. Python 提供了一个 time 和 calendar 模块可以用于格式化日期和时间. 时间间隔是以秒为单位的浮点小数. ...

  9. eclipse 设置字体与自动提示

    1.设置字体与字体大小 至此,字体与大小设置完毕. 2.设置自动提示 在输入框中输入 1-9 a-z A-Z .点击“Apply”保存. 开启JavaScript 自动提示 灰色未激活,先点击复选框激 ...

  10. html和jsp页面中把文本框禁用,只能读不能写的方法

    方法常用有三种: 第一种,使用   onfocus="this.blur()" <input name="deptno" type="text& ...