繁凡出品的全新系列:解题报告系列 —— 超高质量算法题单,配套我写的超高质量题解和代码,题目难度不一定按照题号排序,我会在每道题后面加上题目难度指数(1∼51 \sim 51∼5),以模板题难度 111 为基准。


这样大家在学习算法的时候就可以执行这样的流程:

阅读我的【学习笔记】 / 【算法全家桶】学习算法 ⇒\Rightarrow⇒ 阅读我的相应算法的【解题报告】获得高质量题单 ⇒\Rightarrow⇒ 根据我的一句话题解的提示尝试自己解决问题 ⇒\Rightarrow⇒ 点开我的详细题解链接学习巩固(好耶)
%

题单链接:解题报告(二)多项式问题(多项式乘法及其各种运算)(ICPC / CCPC / NOIP / CF / AT / NC / P)超高质量题解

解题报告(二)E、(BZOJ3513) [MUTC2013] idiots(生成函数 + FFT + 组合计数)

Weblink

https://darkbzoj.tk/problem/3513

Problem

给定 nnn 个长度分别为 aia_iai​ 的木棒,问随机选择 333 个木棒能够拼成三角形的概率。

input

第一行T( T≤100T\le 100T≤100 ),表示数据组数。
接下来若干行描述 T 组数据,每组数据第一行是 n ,接下来一行有 n 个数表示 aia_iai​。

3≤N≤105,1≤ai≤1053≤N≤10^5,1≤a_i≤10^53≤N≤105,1≤ai​≤105

output

T 行,每行一个整数,四舍五入保留7位小数。

Solution

首先我们知道作为一个三角形,两边之和大于第三边。

答案要求的概率很明显就是能组成的三角形的方案数除以总方案数。

如果我们直接去统计一共有多少个符合要求的方案数的话无从下手(好吧,正着做好像也没什么区别),考虑经典正难则反。

我们首先计算总方案数,即从 nnn 个木棒中选择三个,即

tot=Cn3=n×(n−1)×(n−2)/3/2tot=C_{n}^{3}=n\times (n-1)\times (n-2) / 3 / 2tot=Cn3​=n×(n−1)×(n−2)/3/2。

那么我们来尝试统计一下不符合要求的三个木棒的方案数。

不符合要求也就意味着是两个木棒 a,ba,ba,b ,以及一个木棒 ccc ,c≥a+bc\ge a+bc≥a+b,这样就不能组成一个三角形。

因为是统计方案数,且数据较大(10510^5105)不能暴力,只能 O(nlogn)O(nlogn)O(nlogn) 来做,所以经典的 生成函数 + FFT。

所以我们考虑组合计数的思路:

即利用乘法原理,我们只需要求出左半部分 AAA 的个数以及相对应的右半部分 BBB 的个数,相乘并累加即可。

也就是:

我们用 t[i]t[i]t[i] 统计所有大于等于 iii 的木棒的个数。

g[i]g[i]g[i] 表示所有两个木棒的和为 iii 的木棒的个数,那么所有不符合要求的方案数也就是两个木棒 a,ba,ba,b 以及一个 c≥a+bc\ge a+bc≥a+b 的方案数显然就是 illegal=∑i=0maxxg[i]×t[i]\displaystyle illegal=\sum_{i = 0}^{maxx}g[i] \times t[i]illegal=i=0∑maxx​g[i]×t[i] 。

最终的概率显然就是 tot−illegaltot\cfrac{tot-illegal}{tot}tottot−illegal​

那么也就意味着我们只需要计算 g[i]g[i]g[i] 就可以得到答案。

我们考虑如何求得 g[i]g[i]g[i]。

g[i]g[i]g[i] 的实际意义就是 a+b=ia+b=ia+b=i 的方案数,可以理解为选择两个物品 a,ba,ba,b,权值和为 iii 的方案数,显然我们可以用生成函数求解。

我们设 f[i]f[i]f[i] 表示长度为 iii 的木棒数

显然 g[i]=∑f[j]×f[i−j]g[i] = \sum f[j]\times f[i - j]g[i]=∑f[j]×f[i−j]。

一个标准的卷积形式可以直接用 FFT 求解。

但是很明显我们将两个 fff 卷起来会有重复,因为我们只有一个 fff 序列,自己凑,但是生成函数在卷的时候是当成两个相同的 fff 序列卷起来的,例如 1+9=101+9=101+9=10,两个 fff ,所以会有两个 111 和两个 999 ,但实际上只有一个 111 和 1个 999 ,方案数应该是 [1,9],[9,1][1,9],[9,1][1,9],[9,1] 两种,但是生成函数 fff 卷的时候会得到 [1,9],[9,1],[1,9],[9,1][1,9],[9,1],[1,9],[9,1][1,9],[9,1],[1,9],[9,1] 四种方案数,所以最后的方案数要除以 222。并且注意对于序列中仅有一个 555 ,卷的时候会出现 5+5=105+5=105+5=10 这种本来是没有的方案数,如果我们除以二的话也不一定能将其消掉(奇数个除以二下取整会消掉,但万一有偶数个这样的呢)所以我们可以在输入的时候,每次输入 xxx ,就将 g[2×x]−1g[2\times x]-1g[2×x]−1 ,这样就可以将本身不合法的自己加自己(5+5=105+5=105+5=10) 方案数减去。正因如此,我们需要先将 fff 与 ggg 加起来消掉自己加自己之后再除以二消掉冗余的双倍方案。

AC Code

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <map>
#include <queue>
using namespace std;
typedef long long ll;
typedef int itn;
#define int long long
typedef pair<int, int>PII;
const int N = 5e5 + 7, mod = 1e6;
const double PI = acos(-1.0);int n, m, k, L, limit = 1;
int g[N], t[N], RR[N];struct Complex
{double x, y;Complex (double x = 0, double y = 0) : x(x), y(y) { }
}f[N];Complex operator + (Complex a, Complex b) {return Complex (a.x + b.x, a.y + b.y);}
Complex operator - (Complex a, Complex b) {return Complex (a.x - b.x, a.y - b.y);}
Complex operator * (Complex a, Complex b) {return Complex (a.x * b.x - a.y * b.y, a.x * b.y + a.y * b.x);}void FFT(Complex *A, double type)
{for(int i = 0; i < limit; ++ i) {if(i < RR[i])swap(A[i], A[RR[i]]);}for(int mid = 1; mid < limit; mid <<= 1) {Complex wn(cos(PI / mid), type * sin(PI / mid));for(int len = mid << 1, pos = 0; pos < limit; pos += len) {Complex w(1, 0);for(int k = 0; k < mid; ++ k, w = w * wn) {Complex x = A[pos + k];Complex y = w * A[pos + mid + k];A[pos + k] = x + y;A[pos + mid + k] = x - y;}}}if(type == -1) {for(int i = 0; i <= limit; ++ i)A[i].x /= limit;}
}void init()
{memset(g, 0, sizeof g);memset(f, 0, sizeof f);memset(t, 0, sizeof t);}void solve()
{init();scanf("%lld", &n);int maxx = 0;ll tot = (n * (n - 1) * (n - 2)) / 6;for(int i = 1; i <= n; ++ i) {ll x;scanf("%lld", &x);g[x << 1] -- ;t[x] ++ ;f[x].x ++ ;maxx = max(maxx, x);}for(int i = maxx - 1; i >= 1; -- i)t[i] += t[i + 1];//大于等于 i 的木棒数量maxx = maxx - 1 << 1;L = 0, limit = 1;while(limit <= maxx) limit <<= 1, L ++ ;for(int i = 0; i <= limit; ++ i) {RR[i] = (RR[i >> 1] >> 1) | ((i & 1) << (L - 1));}FFT(f, 1);for(int i = 0; i < limit; ++ i) {f[i] = f[i] * f[i];}FFT(f, -1);for(int i = 0; i < limit; ++ i) {g[i] += (int)(f[i].x + 0.5);}for(int i = 0; i < limit; ++ i)g[i] >>= 1;ll illegal = 0;for(int i = 0; i < limit; ++ i) {illegal += g[i] * t[i];}double res = (double)(tot - illegal) / tot;printf("%.7f\n", res);return ;
}signed main()
{itn t;scanf("%lld", &t);while(t -- ) {solve();}return 0;
}

解题报告(二)E、(BZOJ3513) [MUTC2013] idiots(生成函数 + FFT + 组合计数)相关推荐

  1. 2019.01.02 bzoj3513: [MUTC2013]idiots(fft)

    传送门 fftfftfft经典题. 题意简述:给定nnn个长度分别为aia_iai​的木棒,问随机选择3个木棒能够拼成三角形的概率. 思路:考虑对于木棒构造出生成函数然后可以fftfftfft出两个木 ...

  2. 【洛谷新手村解题报告二】C++语言,一题多解,思路和WA反思

    [洛谷新手村解题报告二] 循环!循环!循环! 数组 继续上次的一!开始循环第二题 循环!循环!循环! 第二题 级数求和 [1/2] 已知:Sn= 1+1/2+1/3+-+1/n 显然对于任意一个整数 ...

  3. [精品]CSAPP Bomb Lab 解题报告(二)

    接上篇[精品]CSAPP Bomb Lab 解题报告(一) gdb常用指令 设置Intel代码格式:set disassembly-flavor intel 查看反汇编代码:disas phase_1 ...

  4. 解题报告(二)多项式问题(多项式乘法及其各种运算)(ACM/ OI)超高质量题解

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 繁凡出品的全新系列:解题报告系列 -- 超高质量算法题单,配套我写的超高质量的题解和代码,题目难度不一 ...

  5. 解题报告(四)生成函数(ACM/ OI)

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 繁凡出品的全新系列:解题报告系列 -- 超高质量算法题单,配套我写的超高质量的题解和代码,题目难度不一 ...

  6. [精品]CSAPP Bomb Lab 解题报告(三)

    接上篇[精品]CSAPP Bomb Lab 解题报告(二) gdb常用指令 设置Intel代码格式:set disassembly-flavor intel 查看反汇编代码:disas phase_1 ...

  7. 解题报告(二)C、(darkBZOJ 3771)Triple(生成函数 + FFT + 容斥原理)(3)

    繁凡出品的全新系列:解题报告系列 -- 超高质量算法题单,配套我写的超高质量题解和代码,题目难度不一定按照题号排序,我会在每道题后面加上题目难度指数(1∼51 \sim 51∼5),以模板题难度 11 ...

  8. 解题报告(二)C、(darkBZOJ 2194) 快速傅立叶之二(FFT、卷积的概念、常用变换)

    繁凡出品的全新系列:解题报告系列 -- 超高质量算法题单,配套我写的超高质量题解和代码,题目难度不一定按照题号排序,我会在每道题后面加上题目难度指数(1∼51 \sim 51∼5),以模板题难度 11 ...

  9. LOJ#6103. 「2017 山东二轮集训 Day2」第一题 解题报告

    LOJ#6103. 「2017 山东二轮集训 Day2」第一题 解题报告 前置知识:闭区间上的连续函数的零点存在性定理: 我们定义这样的函数: 定义域为 [ l , r ] ∩ Z [l,r]\cap ...

最新文章

  1. CodeSite使用小结
  2. Oracle分页查询2
  3. 七牛云rs.php位置,七牛云存储PHP生成管理凭证以及查看文件(state)
  4. 粘包问题,以及在python中如何调用操作系统命令
  5. android异步更新UI
  6. 前端lvs访问多台nginx代理服务时出现404错误的处理
  7. 光耦驱动单向可控硅_光耦是什麽?
  8. linux基础知识3
  9. 朴素贝叶斯与贝叶斯网络
  10. 购买域名和GitHub映射
  11. spss回归分析笔记记录
  12. 九度OJ 1349 数字在排序数组中出现的次数 -- 二分查找
  13. phantomjs自动截图生成图片
  14. 【王道考研】操作系统 笔记 第一章
  15. php网盘 开源 web版 手机版
  16. JavaEE——No.2 套接字编程(TCP)
  17. 互联网下半场,苏宁“拼购村”如何打造现象级模式
  18. c语言数据类型与表达式,C语言的基本数据类型与表达式.ppt
  19. Shell 遍历数组的方法
  20. 迷宫求解(深度优先)

热门文章

  1. ResNet及其变体结构梳理与总结
  2. 基于聚类的图像分割-Python
  3. 一个小改动,CNN输入固定尺寸图像改为任意尺寸图像
  4. 实战:使用 OpenCV 的自动驾驶汽车车道检测(附代码)
  5. 12个现实世界中的机器学习真相
  6. 基础知识——测试代码(七)
  7. Angular5学习笔记 - 虚拟RestfulApi配置与使用(六)
  8. 正则表达式学习实例1
  9. textlive在安装完winedt的配置问题
  10. Django中的Form