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. prestashop nginx rewrite rule

    server { listen *:; server_name www.mydomain.com *.mydomain.com; root /var/www/www.mydomain.com/web; ...

  2. 12C -- 配置Application Continuity

     

  3. MeasureSpec 的三中类型

    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools=&qu ...

  4. 读取Excel二进制写入DB,并从DB中读取生成Excel文件

    namespace SendMailSMSService { class Program { static void Main(string[] args) { var connString = Sq ...

  5. linux每日命令(35):grep命令

    Linux系统中grep命令是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹 配的行打印出来.grep全称是Global Regular Expression Print,表示全局正则表达 ...

  6. Smack类库详细介绍

    原文地址:http://blog.csdn.net/xunshu/archive/2008/03/27/2223817.aspx Smack是一个为使用XMPP服务器聊天和发送即时消息交流而提供的库. ...

  7. 【测量实战技术】Cad中导入坐标高程点并可以提取坐标带高程

    一般咱们都是导入cad的是坐标不带高程,那么怎么在cad中导入坐标高程的三维坐标呢,在不需要cass的情况下还能计算方量呢?而且还能批量提取出这些坐标高程的三维参数. 这些都是工作中非常常用的技能,不 ...

  8. Openlayers离线载入天地图

    概述: 经过一个春节的休整,今天最终開始了! 任何时候.都不要忘记学习.学习是一辈子的事情!今天,我来说说怎样实现天地图的离线以及Openlayers载入离线数据实现天地图数据的展示. 实现: 1.获 ...

  9. MongoDB随笔3:使用索引

    创建索引的语句很简单. 1.单键索引的创建:db.test.ensureIndex({name:1},{name:'index_name'}) 2.复合索引的创建:db.test.ensureInde ...

  10. 【转】Windows下charles 使用教程指南

    1.下载就不用再说了,网上好多破解的安装包 2.下面是pc端的抓包使用情况 Charles支持抓去http.https协议的请求,不支持socket.然后charles会自动配置IE浏览器和工具的代理 ...