博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
HDU 4609 3-idiots fft
阅读量:5775 次
发布时间:2019-06-18

本文共 3971 字,大约阅读时间需要 13 分钟。

  题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4609

  题目描述:给出n个数, 问其中选出三个能组成三角形的概率

  解题思路:给出kuangbin巨巨的解题思路, 实在是没有比这儿更好的题解, 所以我就不误导别人和自己了

  http://www.cnblogs.com/kuangbin/archive/2013/07/24/3210565.html

  题目代码:

#include 
#include
#include
#include
#include
using namespace std;const double PI = acos(-1.0);struct Complex { double x, y; Complex(double _x = 0.0, double _y = 0.0) { x = _x; y = _y; } Complex operator -(const Complex &b)const { return Complex(x-b.x, y-b.y); } Complex operator +(const Complex &b)const { return Complex(x+b.x, y+b.y); } Complex operator *(const Complex &b)const { return Complex(x*b.x-y*b.y, x*b.y+y*b.x); }};void change(Complex y[], int len) { int i, j, k;// cout << len << endl;// cout << "-----" << endl; for(i = 1, j = len/2; i < len-1; i++) { if( i < j ) swap(y[i], y[j]); k = len / 2; while( j >= k ) { j -= k; k /= 2;// cout << "----" << endl;// cout << j << " " << k << endl; } if( j < k ) j += k;// cout << "==" << endl; }// cout << "-----" << endl;// cout << "-------------" << endl;}void fft(Complex y[], int len, int on) { change(y, len);// cout << "----" << endl; for(int h = 2; h <= len; h <<= 1) { Complex wn(cos(-on*2*PI/h), sin(-on*2*PI/h)); for(int j = 0; j < len; j+=h) { Complex w(1,0); for(int k = j; k < j+h/2; k++) { Complex u = y[k]; Complex t = w*y[k+h/2]; y[k] = u+t; y[k+h/2] = u-t; w = w*wn; } } } if( on == -1 ) { for( int i = 0; i < len; i++ ) { y[i].x /= len; } }}const int MAXN = 400040;Complex x1[MAXN];int a[MAXN/4];long long num[MAXN];long long sum[MAXN];int main() { int t; int n; scanf( "%d", &t); while( t-- ) { scanf( "%d", &n ); memset( num, 0, sizeof( num ) ); for( int i = 0; i < n; i++ ) { scanf( "%d", &a[i] ); num[a[i]]++; // 记录a[i]出现的次数 }// cout << "=====" << endl; sort(a, a+n); int len1 = a[n-1] + 1; // len 为最长边的界 int len = 1; while( len < 2 * len1 ) len <<= 1; for( int i = 0; i < len1; i++ ) { x1[i] = Complex(num[i], 0); } for( int i = len1; i < len; i++ ) { x1[i] = Complex(0,0); }// cout << "======" << endl; fft(x1, len, 1);// cout << "-----" << endl; for( int i = 0; i < len; i++ ) { x1[i] = x1[i] * x1[i]; } fft(x1, len, -1);// cout << "-----" << endl; for( int i = 0; i < len; i++ ) { num[i] = (long long)(x1[i].x + 0.5); } len = 2 * a[n-1]; // 教程中 界为 2n 必须由 2n 个点来确定 for(int i = 0; i < n; i++ ) { num[a[i]+a[i]]--; // 去重 } for(int i = 1; i <= len; i++ ) { num[i] /= 2; // 卷积后求得是排列数, 组合数除以2 } sum[0] = 0; for( int i = 1; i <= len; i++ ) { sum[i] = sum[i-1] + num[i]; } long long cnt = 0; for( int i = 0; i < n; i++ ) { cnt += sum[len] - sum[a[i]]; // 长度和 大于 a[i] 的个数 cnt -= (long long)(n-1-i)*i; // 减去一大一小 cnt -= (n-1); // 减去包括本身的 cnt -= (long long)(n-1-i)*(n-2-i)/2; // 减去两个大的组合数 } long long tot = (long long)n * (n-1) * (n-2) / 6;// cout << cnt << "===" << tot << endl; printf( "%.7lf\n", (double)cnt / tot ); } return 0;}
View Code

  思考: 首先这道题要让我看到了fft 的一种应用, 那就是排列组合 , 如果遇到加和的组合的可以往fft的方向想, 因为如果a[k]x^k中, k表示 加数时, a[k]代表数量的话, 那么卷积后的a[k']x^k' 中的 加和 k' 的所有排列数位 a[k'] , 因为A^k1 * B^k2 = A^(k1+k2), 这个设计状态也很重要。

      以后要多做题, 多动脑子。

转载于:https://www.cnblogs.com/FriskyPuppy/p/6806074.html

你可能感兴趣的文章
vue中动画的实现的几种方式
查看>>
Iceworks 2.8.0 发布,自定义你的 React 模板
查看>>
胖哥学SpringMVC:请求方式转换过滤器配置
查看>>
Kotlin 更加优雅的 Builder - 理解 with
查看>>
JVM 系列文章之 Full GC 和 Minor GC
查看>>
iOS Autolayout的一点小坑
查看>>
跨域资源共享CORS
查看>>
Java并发——信号量Semaphore
查看>>
swift 存放多类型的容器
查看>>
说说RxJava怎么走的歪路
查看>>
Markdown使用入门
查看>>
分享一个生成builder class的插件
查看>>
跳槽时,这些Java面试题99%会被问到
查看>>
多彩的 console.log
查看>>
阿里云HBase推出全新X-Pack服务 定义HBase云服务新标准
查看>>
赋能时空云计算 阿里云数据库时空引擎Ganos上线
查看>>
前端日拱一卒D6——字符编码与浏览器解析
查看>>
Nginx 解决浏览器 Ajax 跨域问题
查看>>
如何写出一个好的单例模式
查看>>
swift的基础语法(一)
查看>>