[hdu4609]计数方法,FFT
题目:给一个数组a,从里面任选三个数,求以这三个数为三条边能构成三角形的概率。
思路:由于每个数只能用一次,所以考虑枚举三边中的最大边。先将a数组排序,然后枚举它的每个数x作为最大边,那么问题就是要求在数组a剩余的数里面“找小于等于x”且“和大于x”的数对个数,答案显然不能直接得到。不妨先计算这样一个数组ans[i]:表示在数组a里面有放回的选两个数,和为i的数对个数。设cnt[i]为i这个数在a数组里面出现的次数,那么ans相当于cnt对cnt的卷积结果, 这可以利用FFT在nlogn的时间内求得。ans数组出来以后,由于还需要将它变成“无放回地取两个数”的结果,且要保证答案的无序性(由于每个答案都会被统计两次,全部除以2即可),需要做些处理,具体见代码。处理完后,ans[i]表示从a数组里面任选两个数和为i的方案数,就可以利用ans来得到答案了。
先对ans进行前缀和处理(ans[i]+=ans[i-1]),在枚举到最大边x时,另两边的和可以为x+1~maxsum的任意值,将答案加上ans[maxsum] - ans[x]---(1),由于加的这个答案里面包含很多不合法的,需要一一减去,下面对不合法的进行分类{设共n个数,范围为[a,a+n),现在枚举到了i这个位置,数为x,需要注意的是由于已经排序,下面的大小关系是指位置的大小关系,而不用特别去考虑相等情况了}:
(1)两边都大于x,显然它们的和大于x,所以会出现在(1)里面,需要减去: (n-i-1)*(n-i-2)/2
(2)一边大于x,一边小于x,显然它们的和也大于x,会出现在(1)里面,需要减去:i*(n-i-1)
(3)一边等于x,一边不等于x,显然他们的和也大于x,会出现在(1)里面,需要减去:n-1
这样枚举完所有数,就得到答案了。
另外,整体看减去的数,是一个常数,而枚举每个数累加的ans值跟次序无关 ,于是根本无需排序,一样得到正确的结果。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
|
/* ******************************************************************************** */#include <iostream> //#include <cstdio> //#include <cmath> //#include <cstdlib> //#include <cstring> //#include <vector> //#include <ctime> //#include <deque> //#include <queue> //#include <algorithm> //#include <map> //#include <cmath> //using namespace std; // //#define pb push_back //#define mp make_pair //#define X first //#define Y second //#define all(a) (a).begin(), (a).end() //#define fillchar(a, x) memset(a, x, sizeof(a)) // //void RI(vector<int>&a,int n){a.resize(n);for(int i=0;i<n;i++)scanf("%d",&a[i]);} //void RI(){}void RI(int&X){scanf("%d",&X);}template<typename...R> //void RI(int&f,R&...r){RI(f);RI(r...);}void RI(int*p,int*q){int d=p<q?1:-1; //while(p!=q){scanf("%d",p);p+=d;}}void print(){cout<<endl;}template<typename T> //void print(const T t){cout<<t<<endl;}template<typename F,typename...R> //void print(const F f,const R...r){cout<<f<<", ";print(r...);}template<typename T> //void print(T*p, T*q){int d=p<q?1:-1;while(p!=q){cout<<*p<<", ";p+=d;}cout<<endl;} // //typedef pair<int, int> pii; //typedef long long ll; //typedef unsigned long long ull; // //template<typename T>bool umax(T&a, const T&b){return b<=a?false:(a=b,true);} //template<typename T>bool umin(T&a, const T&b){return b>=a?false:(a=b,true);} //template<typename T> //void V2A(T a[],const vector<T>&b){for(int i=0;i<b.size();i++)a[i]=b[i];} //template<typename T> //void A2V(vector<T>&a,const T b[]){for(int i=0;i<a.size();i++)a[i]=b[i];} // //const double PI = acos(-1); // ///* -------------------------------------------------------------------------------- */namespace FFT { const static int maxn = 1e5 + 7; #define L(x) (1 << (x)) double ax[maxn << 2], ay[maxn << 2], bx[maxn << 2], by[maxn << 2];//需要四倍空间 int revv(int x, int bits) { int ret = 0; for (int i = 0; i < bits; i++) { ret <<= 1; ret |= x & 1; x >>= 1; } return ret; } void fft(double * a, double * b, int n, bool rev) { int bits = 0; while (1 << bits < n) ++bits; for (int i = 0; i < n; i++) { int j = revv(i, bits); if (i < j) swap(a[i], a[j]), swap(b[i], b[j]); } for (int len = 2; len <= n; len <<= 1) { int half = len >> 1; double wmx = cos(2 * PI / len), wmy = sin(2 * PI / len); if (rev) wmy = -wmy; for (int i = 0; i < n; i += len) { double wx = 1, wy = 0; for (int j = 0; j < half; j++) { double cx = a[i + j], cy = b[i + j]; double dx = a[i + j + half], dy = b[i + j + half]; double ex = dx * wx - dy * wy, ey = dx * wy + dy * wx; a[i + j] = cx + ex, b[i + j] = cy + ey; a[i + j + half] = cx - ex, b[i + j + half] = cy - ey; double wnx = wx * wmx - wy * wmy, wny = wx * wmy + wy * wmx; wx = wnx, wy = wny; } } } if (rev) { for (int i = 0; i < n; i++) a[i] /= n, b[i] /= n; } } int solve(ll a[], int na, ll b[], int nb, ll ans[]) { int len = max(na, nb), ln; for(ln = 0; L(ln) < len; ++ln); len = L(++ln); for (int i = 0; i < len ; ++i) { if (i >= na) ax[i] = 0, ay[i] = 0; else ax[i] = a[i], ay[i] = 0; } fft(ax, ay, len, 0); for (int i = 0; i < len; ++i) { if (i >= nb) bx[i] = 0, by[i] = 0; else bx[i] = b[i], by[i] = 0; } fft(bx, by, len, 0); for (int i = 0; i < len; ++i) { double cx = ax[i] * bx[i] - ay[i] * by[i]; double cy = ax[i] * by[i] + ay[i] * bx[i]; ax[i] = cx, ay[i] = cy; } fft(ax, ay, len, 1); for (int i = 0; i < len; ++i) ans[i] = (ll)(ax[i] + 0.5); return len; } #undef L(x)}const int maxn = 1e5 + 7;ll c[maxn << 2], d[maxn << 2], ans[maxn << 2], sum[maxn << 2];int a[maxn];int main() {#ifndef ONLINE_JUDGE freopen("in.txt", "r", stdin);#endif // ONLINE_JUDGE int T, n; cin >> T; while (T --) { fillchar(c, 0); fillchar(d, 0); fillchar(ans, 0); cin >> n; int maxv = 0; for (int i = 0; i < n; i ++) { RI(a[i]); c[a[i]] ++; umax(maxv, a[i]); } maxv ++; for (int i = 0; i < maxv; i ++) d[i] = c[i]; int L = FFT::solve(c, maxv, d, maxv, ans); while (ans[L] <= 0 && L > 1) L --; L ++; for (int i = 0; i < n; i ++) ans[a[i] << 1] --; for (int i = 1; i < L; i ++) { ans[i] >>= 1; sum[i] = sum[i - 1] + ans[i]; } ll Result = 0, Total = (ll)n * (n - 1) * (n - 2) / 6; //sort(a, a + n); for (int i = 0; i < n; i ++) { ll buf = sum[L - 1] - sum[a[i]]; buf -= n - 1; buf -= (ll)i * (n - i - 1); buf -= (ll)(n - i - 1) * (n - i - 2) / 2; Result += buf; } printf("%.7f\n", (double)Result / Total); } return 0;}/* ******************************************************************************** */ |
[hdu4609]计数方法,FFT的更多相关文章
- 【spring data jpa】jpa中使用count计数方法
spring data jpa中使用count计数方法很简单 直接在dao层写方法即可 int countByUidAndTenementId(String parentUid, String ten ...
- 【概率论】1-2:计数方法(Counting Methods)
title: [概率论]1-2:计数方法(Counting Methods) categories: Mathematic Probability keywords: Counting Methods ...
- 有标号的DAG计数(FFT)
有标号的DAG计数系列 有标号的DAG计数I 题意 给定一正整数\(n\),对\(n\)个点有标号的有向无环图(可以不连通)进行计数,输出答案\(mod \ 10007\)的结果.\(n\le 500 ...
- 【hdu4609】 3-idiots FFT
题外话:好久没写blog了啊-- 题目传送门 题目大意:给你m条长度为ai的线段,求在其中任选三条出来,能构成三角形的概率.即求在这n条线段中找出三条线段所能拼出的三角形数量除以$\binom{m}{ ...
- [HDU4609]3-idiots(生成函数+FFT)
3-idiots Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total S ...
- php导出excel长数字串显示为科学计数方法与最终解决方法
1.设置单元格为文本 $objPHPExcel = new PHPExcel(); $objPHPExcel->setActiveSheetIndex(0); $objPHPExcel-> ...
- UOJ#335. 【清华集训2017】生成树计数 多项式,FFT,下降幂,分治
原文链接www.cnblogs.com/zhouzhendong/p/UOJ335.html 前言 CLY大爷随手切这种题. 日常被CLY吊打系列. 题解 首先从 pruffer 编码的角度考虑这个问 ...
- bzoj1272 Gate Of Babylon(计数方法+Lucas定理+乘法逆元)
Description Input Output Sample Input 2 1 10 13 3 Sample Output 12 Source 看到t很小,想到用容斥原理,推一下发现n种数中选m个 ...
- loj6570 毛毛虫计数(生成函数FFT)
link 巨佬olinr的题解 <-- olinr很强 考虑生成函数 考虑直径上点数>=4的毛毛虫的直径,考虑直径中间那些节点以及他上面挂的那些点的EGF \(A(x)=\sum_{i\g ...
随机推荐
- Python 3.9 性能优化:更快的 list()、dict() 和 range() 等内置类型
Python 的 3.9.0 版本正在开发中,计划在 2020-10-05 发布 final 版本. 官方在 changelog 中披露了很多细节,其中有一项"vectorcall" ...
- APP测试和WEB测试区别
App测试web测试的区别 单纯从功能测试的层面上来讲的话,APP 测试.web 测试 在流程和功能测试上是没有区别的 根据两者载体不一样,则区别如下: 1.兼容性测试:web端兼容浏览器,app端兼 ...
- 6. webRTC
webrtc网上封装的很多,demo很多都是一个页面里实现的,今天实现了个完整的 , A 发视频给 B. 1.) A 方 <!DOCTYPE html> <html id=" ...
- 人体和电脑的关系——鸟哥的LINUX私房菜基础学习篇读书笔记
CUP=脑袋: 每个人会做的事情都不一样(指令集的差异),但主要都是通过脑袋来判断与控制身体各部分的行动 内存=脑袋中存放正在思考的数据区块: 在实际活动过程中,我们的脑袋需要有外界刺激的数据(例如光 ...
- 调用ocx ActiveX控件详解(做一个简单的ocx控件)
背景 最近做的项目都和插件有关,就是在页面中调用插件的方法,然后进行操作. 插件就是ocx ActiveX控件,具体的说明可以自己去了解一下,在这里就不做赘述. 具体调用方式很简单: 1.在页面中写一 ...
- wincache 与 zend guard 的冲突
ZendLoader.dll 与wincache.dll 同时开启 问题分析:zend与wincache冲突 解决方法: 关掉wincache: 在php.ini中的 extension=php_w ...
- Adobe Flash player 过期
完美解决问题的办法,在百度中输入 "adobe flash player debugger",如图进入官网 选择对应操作系统的对应版本,下载安装,重启浏览器,一切ok IE内核浏览 ...
- python学习24之异常
'''''''''1.低级错误:纯语法错误2.中级错误:代码存在隐性错误,逻辑缺陷3.高级错误:软件面对不确定性的异常错误''''''一.捕获异常1.基本异常捕获语句try: #异常捕捉语句的开始 代 ...
- Python带你做个愉快的"动森"玩家! (超简单代码)
最近Switch上的<动物森友会>可谓是炙手可热,它几乎算是任天堂版的<模拟人生>了,它的最新游戏<集合啦!动物森友会>(以下称“动森”)在发售后,取得了不错的媒体 ...
- Win10 及 Google 浏览器显示界面异常
win10 和 google 界面显示异常 win10 个别 ui 组件花屏,google 界面直接黑屏 解决方式 更新集成显卡或者重装显卡驱动,最好使用 驱动人生 !!!