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 组合数学题的更多相关文章

  1. HDU4609 FFT+组合计数

    HDU4609 FFT+组合计数 传送门:http://acm.hdu.edu.cn/showproblem.php?pid=4609 题意: 找出n根木棍中取出三根木棍可以组成三角形的概率 题解: ...

  2. 组合数学题 Codeforces Round #108 (Div. 2) C. Pocket Book

    题目传送门 /* 题意:每一次任选i,j行字符串进行任意长度前缀交换,然后不断重复这个过程,问在过程中,第一行字符串不同的个数 组合数学题:每一列不同的字母都有可能到第一行,所以每列的可能值相乘取模就 ...

  3. HDU4609 3-idiots(母函数 + FFT)

    题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=4609 Description King OMeGa catched three men wh ...

  4. BZOJ.3771.Triple(母函数 FFT 容斥)

    题目链接 \(Description\) 有\(n\)个物品(斧头),每个物品价值不同且只有一件,问取出一件.两件.三件物品,所有可能得到的价值和及其方案数.\((a,b),(b,a)\)算作一种方案 ...

  5. UVa12298 Super Poker II(母函数 + FFT)

    题目 Source http://acm.hust.edu.cn/vjudge/problem/23590 Description I have a set of super poker cards, ...

  6. 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是第二类斯特林 ...

  7. 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是第二类斯特林 ...

  8. SPOJ - TSUM 母函数+FFT+容斥

    题意:n个数,任取三个加起来,问每个可能的结果的方案数. 题解:构造母函数ABC,比如现在有 1 2 3 三个数.则 其中B表示同一个数加两次,C表示用三次.然后考虑去重. A^3表示可重复地拿三个. ...

  9. SPOJ:Triple Sums(母函数+FFT)

    You're given a sequence s of N distinct integers.Consider all the possible sums of three integers fr ...

随机推荐

  1. linux下编译安装pthreads扩展

    这里讲的是如何编译安装pthreads,以后编译安装其他PHP扩展可以参考此方法. 下载pthreads源码:http://pecl.php.net/package/pthreads 首先确定安装的p ...

  2. [k8s]通过openssl生成证书

    证书认证原理: http://www.cnblogs.com/iiiiher/p/7873737.html [root@m1 ssl]# cat master_ssl.cnf [req] req_ex ...

  3. docker的swarm介绍

    转载自:https://blog.csdn.net/karamos/article/details/80132082 另外一篇:https://www.jianshu.com/p/9eb9995884 ...

  4. 系统用户在Samba服务器中起一个别名

    (1)通过/etc/samba/smbusers文件设置用户映射关系 如实列: # cat /etc/samba/smbusers # Unix_name = SMB_name1 SMB_name2 ...

  5. Python中的zip()与*zip()函数详解

    前言 实验环境: Python 3.6: 示例代码地址:下载示例: 本文中元素是指列表.元组.字典等集合类数据类型中的下一级项目(可能是单个元素或嵌套列表). zip(*iterables)函数详解 ...

  6. supervisor详解

    1.什么是supervisor supervisor是用python写的一个进程管理工具,用来启动,重启,关闭进程. 2.supervisor的安装 pip install supervisor 3. ...

  7. linux每日命令(32):gzip命令

    减少文件大小有两个明显的好处,一是可以减少存储空间,二是通过网络传输文件时,可以减少传输的时间.gzip是在Linux系统中经常使用的一个对文件进行压缩和解压缩的命令,既方便又好用.gzip不仅可以用 ...

  8. Vue.js常用指令:v-show和v-if

    一.v-show指令 v-show指令可以用来动态的控制DOM元素的显示或隐藏.v-show后面跟的是判断条件,语法如下: v-show="判断变量" 例如: v-show=&qu ...

  9. hello alibaba

    http://ifeve.com/dubbo-learn-book/ http://ifeve.com/leader-follower-thread-model/ http://ifeve.com/a ...

  10. Hibernate HQL的使用

    1.简单查询(查询所有) Session session=HibernateUtil.getSessionFactory().getCurrentSession(); Transaction tx=s ...