3-idiots hdu4609 母函数+FFT 组合数学题
http://acm.hdu.edu.cn/showproblem.php?pid=4609
题意:1e5个数,求取三个数能形成三角形的概率。
题解(这怎么会是fft入门题QAQ):
概率的算法就是三角形取法/总取法。总取法就是C(n,3).
三角形取法如何计算?
part1:构造母函数F(日常套路),每一项的次数为长度,系数为该长度的木棍数量,用FFT算F^2 ,
得到的多项式就包含了任意取两跟棍子得到的所有长度的方案数:其中次数为两根棍长之和,系数为该长度的方案数,
part2:去重,考虑part1中得到的系数,并非方案数(举个例子,(a+b)^2==a^2+b^2+2ab)
首先,对于每个平方项,因为棍子不能重复使用,所以对于k^m要减去平方前k^(m/2)的系数,
其次,对于剩下的每一项,由于多项式乘法每个乘法都做了两遍,所以得到的系数为方案数的两倍。要/2.
我们将处理过的系数存入数组A。
part3:算方案数:为了避免重复,对于每一根的木棍,计算以它为最长边的三角形方案数:为该长度到最大长度的A的系数和,(前缀和O(1)算出)
减去其中包含它的方案数,为1*(n-1).
减去其中它不是最长的方案数,为(n-1-1)*比它长的木棍数-两根都比它长的方案数/2(乘法原理多算了一遍,容斥减去),也可以理解为 一根比它长一根比他短+两根都比他长/2.(其中比它长的木棍数并不需要树状数组,只要排个序,他就是n-i)
end
总之,fft只是一个开始,后面巨麻烦orz
坑:套miskcoo dalao的fft,结果发现别人的是魔改版的,需要深刻地理解fft才会用orz
ac代码:
#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
#include<iomanip>
#include<complex>
using namespace std;
//const double eps(1e-8);
typedef long long lint; const double PI = acos(-1.0); const int MaxL = , MaxN = << MaxL;
typedef complex<double> complex_t;
complex_t f[MaxN], g[MaxN];
complex_t eps[MaxN], inv_eps[MaxN];
void init_eps(int p)
{
double pi = acos(-);
//double angle = 2.0 * pi / p;
for (int i = ; i != p; ++i)
eps[i] = complex_t(cos(2.0 * pi * i / p), sin(2.0 * pi * i / p));
for (int i = ; i != p; ++i)
inv_eps[i] = conj(eps[i]);
} void transform(int n, complex_t *x, complex_t *w)
{
for (int i = , j = ; i != n; ++i)
{
if (i > j) std::swap(x[i], x[j]);
for (int l = n >> ; (j ^= l) < l; l >>= );
} for (int i = ; i <= n; i <<= )
{
int m = i >> ;
for (int j = ; j < n; j += i)
{
for (int k = ; k != m; ++k)
{
complex_t z = x[j + m + k] * w[n / i * k];
x[j + m + k] = x[j + k] - z;
x[j + k] += z;
}
}
}
} int branch[];
int num[];
complex_t a[];//(1 << 17 = 131072, 1 << 18 = 262144)
lint A[];
lint sumA[];//表示A[i]的前缀和 int main()
{
int T, n;
scanf("%d", &T);
while (T--)
{
scanf("%d", &n);
int maxBranch = ;
for (int i = ; i < n; i++)
{
scanf("%d", branch + i);
maxBranch = max(maxBranch, branch[i]);
}
memset(num, , sizeof(num));
for (int i = ; i < n; i++)
num[branch[i]]++;
for (int i = ; i <= maxBranch; i++)
a[i] = num[i];
int len = ;
while (len <= maxBranch) len <<= ;
len <<= ;
for (int i = maxBranch + ; i < len; i++)
a[i] = 0.0;
init_eps(len);
transform( len,a ,eps);
for (int i = ; i < len; i++)
a[i] = a[i] * a[i];
transform( len,a, inv_eps);
for (int i = ; i <= * maxBranch; i++)
A[i] = (lint)(a[i].real() + 0.5)/len;
for (int i = ; i <= * maxBranch; i += )
A[i] -= num[i >> ];
for (int i = ; i <= * maxBranch; i++)
A[i] /= ;
//到现在为止A[i]表示的是取两根不同的branch的长度和为i的组合种数
sumA[] = ;
for (int i = ; i <= * maxBranch; i++)
sumA[i] = sumA[i - ] + A[i];
lint ans = ;
sort(branch, branch + n);
for (int i = ; i <= n; i++)//以第i根作为边最长的
{
lint tmp = sumA[ * maxBranch] - sumA[branch[i]];//另外两条边长度和要大于branch[i]
tmp -= (lint)(n - i)*(n - );//比它长
tmp += (lint)(n - i)*(n - i - ) / ;//两条都比他长
tmp -= n - ;//另外两条的组合中包括它自己的组合
ans += tmp;
}
double p = ans * . / n / (n - ) / (n - );
printf("%.7f\n", p);
}
cin >> n;
return ;
}
/*
*/
/*
2
4
1 3 3 4
4
2 3 3 4 */
3-idiots hdu4609 母函数+FFT 组合数学题的更多相关文章
- HDU4609 FFT+组合计数
HDU4609 FFT+组合计数 传送门:http://acm.hdu.edu.cn/showproblem.php?pid=4609 题意: 找出n根木棍中取出三根木棍可以组成三角形的概率 题解: ...
- 组合数学题 Codeforces Round #108 (Div. 2) C. Pocket Book
题目传送门 /* 题意:每一次任选i,j行字符串进行任意长度前缀交换,然后不断重复这个过程,问在过程中,第一行字符串不同的个数 组合数学题:每一列不同的字母都有可能到第一行,所以每列的可能值相乘取模就 ...
- HDU4609 3-idiots(母函数 + FFT)
题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=4609 Description King OMeGa catched three men wh ...
- BZOJ.3771.Triple(母函数 FFT 容斥)
题目链接 \(Description\) 有\(n\)个物品(斧头),每个物品价值不同且只有一件,问取出一件.两件.三件物品,所有可能得到的价值和及其方案数.\((a,b),(b,a)\)算作一种方案 ...
- UVa12298 Super Poker II(母函数 + FFT)
题目 Source http://acm.hust.edu.cn/vjudge/problem/23590 Description I have a set of super poker cards, ...
- BZOJ 4555: [Tjoi2016&Heoi2016]求和 [分治FFT 组合计数 | 多项式求逆]
4555: [Tjoi2016&Heoi2016]求和 题意:求\[ \sum_{i=0}^n \sum_{j=0}^i S(i,j)\cdot 2^j\cdot j! \\ S是第二类斯特林 ...
- BZOJ 4555: [Tjoi2016&Heoi2016]求和 [FFT 组合计数 容斥原理]
4555: [Tjoi2016&Heoi2016]求和 题意:求\[ \sum_{i=0}^n \sum_{j=0}^i S(i,j)\cdot 2^j\cdot j! \\ S是第二类斯特林 ...
- SPOJ - TSUM 母函数+FFT+容斥
题意:n个数,任取三个加起来,问每个可能的结果的方案数. 题解:构造母函数ABC,比如现在有 1 2 3 三个数.则 其中B表示同一个数加两次,C表示用三次.然后考虑去重. A^3表示可重复地拿三个. ...
- SPOJ:Triple Sums(母函数+FFT)
You're given a sequence s of N distinct integers.Consider all the possible sums of three integers fr ...
随机推荐
- pureftpd.passwd解析
将pureftpd.passwd文件的内容转换成sql语句,导入到mysql pureftp.passwd格式: <account>:<password>:<uid> ...
- loadrunner 关联匹配多个值
loadrunner 关联获取从服务器返回相关值,如果需要把所有匹配的值都获取并且把这些值打印出来,怎么做呢? 1.首先要把把所有的匹配值都保存起来,需要在关联函数里面多传递一个参数:"Or ...
- HTML Entity 字符实体(字符转义)
目录 1. HTML Entity 2. 字符与Entity Name的互相转换 3. 字符与Entity Number的互相转换 1. HTML Entity 1.1 介绍 在编写HTML页面时,需 ...
- Linux安装R记要
R在Linux上的安装有一些坑(Windows上安装会方便许多),在这里记录,希望可以减少读者不必要的麻烦.我的服务器是SUSE Linux 64位,无法接入互联网(安全原因,你懂的). 到R官网ht ...
- JsonCpp 的使用
JSON全称为JavaScript ObjectNotation,它是一种轻量级的数据交换格式,易于阅读.编写.解析.jsoncpp是c++解析JSON串常用的解析库之一. jsoncpp中主要的类: ...
- 【Java】浅谈Java IO
注意 本文的代码,为了学习方便,简化代码复杂度,未考虑拆包.粘包等情况的处理.所以仅供学习使用,不能用于实际环境. 阻塞IO,BIO Java1.1发布的IO是BIO.阻塞地连接之后,通过流进行同步阻 ...
- 使用python抓取58手机维修信息
之前在ququ的博客上看到说 python 中的BeautifulSoup 挺好玩的,今天下午果断下载下来,看了下api,挺好用的,完了2把,不错. 晚上写了一个使用python抓取58手机维修信息的 ...
- [转]PowerDesigner大小写转换
原文地址:https://blog.csdn.net/fzqlife/article/details/72769959?utm_source=blogxgwz7 在菜单栏找到:Tools-->E ...
- Java知多少(54)断言详解
断言的概念 断言用于证明和测试程序的假设,比如“这里的值大于 5”.断言可以在运行时从代码中完全删除,所以对代码的运行速度没有影响. 断言的使用 断言有两种方法: 一种是 assert<< ...
- MYSQL + MHA +keepalive + VIP安装配置(二)--MHA的配置
一.总概 1.MHA介绍 MHA(Master High Availability)是自动的master故障转移和Slave提升的软件包.它是基于标准的MySQL复制(异步/半同步). MH ...