终于来了! 这道题目.

题目描述:
King OMeGa catched three men who had been streaking in the street. Looking as idiots though, the three men insisted that it was a kind of performance art, and begged the king to free them. Out of hatred to the real idiots, the king wanted to check if they were lying. The three men were sent to the king's forest, and each of them was asked to pick a branch one after another. If the three branches they bring back can form a triangle, their math ability would save them. Otherwise, they would be sent into jail.
However, the three men were exactly idiots, and what they would do is only to pick the branches randomly. Certainly, they couldn't pick the same branch - but the one with the same length as another is available. Given the lengths of all branches in the forest, determine the probability that they would be saved.

输入:
An integer T(T≤100) will exist in the first line of input, indicating the number of test cases.
Each test case begins with the number of branches N(3≤N≤105).
The following line contains N integers a_i (1≤a_i≤105), which denotes the length of each branch, respectively.

输出:
Output the probability that their branches can form a triangle, in accuracy of 7 decimal places.

样例输入:
2
4
1 3 3 4
4
2 3 3 4

样例输出:
0.5000000
1.0000000

题目的意思很简单, 给你一堆长度各异的棍子, 棍子的数量和每根棍子有多长也告诉你, 问你随便拿三根可以组成三角形的概率是多少, (所以3个滞胀只是用来吐槽的, 并没有什么实际的题意)

如果暴力当然是超时啦...

再怎么优化都没用的,肯定超时....

除非你有什么黑科技.....

呃, 一个不那么黑科技的东西就是使用FFT来优化.

如何优化, 当然是用多项式了, 想一下生成函数, 可以获得一个任取两根棍子获得长度的生成数组

首先先是FFT来进行多项式相乘, 然后得到一个生成函数的系数数组.

但是, 里面会有重复的, 这里是第一个去重, 比较容易想到

先想一下这个多项式相乘什么意思, 就是两堆一模一样的棍子, 第一堆随便拿一根, 第二堆随便拿一根

那么会多出来这么两种情况 1.两堆里面拿出来的两根棍子是一样的 2.第一堆拿了第a根棍子 第二堆拿了第b根棍子 这种情况和 第一堆拿了第b根棍子 第二堆拿了第a根棍子 是一样的.

针对情况一, 先遍历这一堆里面的每一根棍子, 把长度*2的次数(生成函数的系数)减一, 解决了情况1的重复

然后, 把所有的项的系数都除以2, 就解决了情况2的重复.

然后我们就得到了一个数组, 就是在一堆里面任取两根长度为何的生成数组(times[5]=4的意思是 任取两根棍子长度恰为5的方案数是4)

不过说实话这只是万里长征第一步, 后面的去重才麻烦着呢......

由于前面的操作, 我们要对原始的存储棍子的数组进行排序. 这里对每根棍子进行遍历, 求针对每根棍子有几种(不重复的)方案.

遍历时, 针对特定的棍子(比如到第i根棍子), 先不妨假设这跟棍子是最长的.

当然了,不管它是不是最长的, 它的长度一定是短于(小于!)其他两根棍子长度之和的, 所以把生成函数系数数组里面下标大于这根特定的棍子长度的数据加起来, 这里为了减少时间, 我们先处理出前缀和数组sum[], 这样结果就是sum[len]-sum[data[i]], 其中len是最大脚标, data[i]是特定棍子的长度.

如何保证它是不重复的呢? 关键就是前面提到的"不妨假设这跟棍子是最长的"

那么保证去重的正确性就是保证这根棍子是最长的. 对于刚刚算出来的sum[len]-sum[data[i]], 里面有一些错误的方案, 这是要去掉的.(下面的式子都是保证已经对data数组排过序之后的从0~n-1之间的遍历!)

1.这跟棍子并不是最大的之---它是最小的, 这种错误的方案数是 (n-i-1)*(n-i-2)/2

2.这根棍子并不是最大的之---有一根比它长, 另一根比它短, 这种错误的方案数是 (n-i-1)*i

3.咦, 为什么拿出来的两根棍子有一根也是第i根?---组合里面会有包含自己的, 这种错误的方案数是 n-1

至于方案数为什么是这么些, 这就是你组合数学的功底了, 跟我没关系.

然后减掉就行.

还有就是, 关于强制类型转换, 我真的心累啊.....一个都不能不一样的啊......

代码如下:

#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <algorithm>
using namespace std;
const double PI=acos(-1);struct complex
{double a,b;//a表示实部,b表示虚部complex(double aa=0.0,double bb=0.0){a=aa;b=bb;}complex operator +(const complex &e){return complex(a+e.a,b+e.b);}complex operator -(const complex &e){return complex(a-e.a,b-e.b);}complex operator *(const complex &e){return complex(a*e.a-b*e.b,a*e.b+b*e.a);}
};void change(complex *y,int len)
{int i,j,k;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>>=1;}if(j<k){j+=k;}}
}
void fft(complex *y,int len,int on)
{change(y, len);int i,j,k;for(i=2;i<=len;i<<=1){complex wn(cos(-on*2*PI/i),sin(-on*2*PI/i));for(j=0;j<len;j+=i){complex w(1,0);for(k=j;k<j+i/2;k++){complex u=y[k],t=w*y[k+i/2];y[k]=u+t;y[k+i/2]=u-t;w=w*wn;}}}if(on==-1)for(i=0;i<len;i++)y[i].a/=len;
}const int maxx=500000;
complex a[maxx],b[maxx];
long long int sum[maxx];
int data[maxx];
long long int times[maxx];
int len,len_a;
//怕函数体里面塞不下所以.....int main()
{int T,n,i;double res;long long int yes,all;scanf("%d",&T);while(T--){yes=all=res=0;len=1;len_a=0;memset(times,0,sizeof(times));memset(a,0,sizeof(a));memset(b,0,sizeof(b));scanf("%d",&n);for(i=0;i<n;i++){scanf("%d",&data[i]);times[data[i]]++;len_a=max(len_a,data[i]);}len_a++;sort(data,data+n);while(len<(2*len_a))len=len<<1;for(i=0;i<len;i++)a[i].a=times[i];fft(a,len,1);for(i=0;i<len;i++)b[i]=a[i]*a[i];fft(b,len,-1);for(i=0;i<len;i++)times[i]=(long long int)(0.5+b[i].a);len=2*data[n-1];//更新len!for(i=0;i<n;i++)times[data[i]*2]--;for(i=0;i<=len;i++)//这里中间为什么是等于?times[i]=times[i]/2;sum[0]=times[0];for(i=1;i<=len;i++)//这里中间为什么也是等于?sum[i]=sum[i-1]+times[i];//求前缀和for(i=0;i<n;i++){yes+=sum[len]-sum[data[i]];yes-=(long long)(n-1-i)*i;yes-=(n-1);yes-=(long long)(n-1-i)*(n-i-2)/2;//关键是这里的去重和去掉的不符合题目的部分!}all=(long long)n*(n-1)*(n-2)/6;res=(double)yes/all;printf("%.7lf\n",res);}return 0;
}

2018-01-20 HDU 4609 FFT 快速傅里叶变换相关推荐

  1. 【经典算法实现 44】理解二维FFT快速傅里叶变换 及 IFFT快速傅里叶逆变换(迭代法 和 递归法)

    [经典算法实现 44]理解二维FFT快速傅里叶变换 及 IFFT快速傅里叶逆变换(迭代法 和 递归法) 一.二维FFTFFTFFT快速傅里叶变换 公式推导 二.二维FFTFFTFFT 及 IFFTIF ...

  2. FFT快速傅里叶变换 超详细的入门学习总结

    FFT快速傅里叶变换 说明 本文创作的目的是为自己巩固该算法,加深印象并深入理解,同时也为FFT入门学者提供一份可鉴的学习总结. 原文链接:https://blog.csdn.net/qq_39565 ...

  3. FFT快速傅里叶变换C语言实现信号处理 对振动信号进行实现时域到频域的转换

    FFT快速傅里叶变换C语言实现信号处理 对振动信号进行实现时域到频域的转换,可实现FFT8192个点或改成其他FFT1024.4096等等,可以直接运行,运行结果与matlab运行的一致,写好了注释, ...

  4. c语言fft乘法步骤,C语言实现FFT(快速傅里叶变换).doc

    C语言实现FFT(快速傅里叶变换) 择蚁牙幸帆揣邓淌港烬粹甩滋整维含兔忿茂慨渔下餐随扼哇房坏鹅穆礼围引介害芝共茨恿把喜恤寇杖除冕嗓停揍猫调锚遭傀个碱晓频斌硕宾撕坪莱哩腊养掘蹄轴国繁蔬虞靡砖焙倍勾呸怀怒 ...

  5. 快速傅里叶变换c语言函数,C语言实现FFT(快速傅里叶变换)

    while(1); } #include #include /********************************************************************* ...

  6. 如何 FFT(快速傅里叶变换) 求幅度、频率(超详细 含推导过程)

    目录 如何 FFT(快速傅里叶变换) 求幅度.频率(超详细 含推导过程) 一. 打颗栗子 二. 求幅度 1. 快速傅里叶变换 2. 求出复数的绝对值 3. 归一化 小结 三. 求频率 1. 频率公式 ...

  7. FFT快速傅里叶变换的应用——画单边频谱图matlab

    FFT快速傅里叶变换的应用--画单边频谱图matlab 快速傅里叶变换在数字信号处理里用的十分广泛,在matlab仿真中,处理信号的时频域变换十分有效,这里结合两个做过的仿真,来说一说fft的应用:画 ...

  8. fft2MATLAB内存不足,matlab中fft快速傅里叶变换

    博文来源:https://ww2.mathworks.cn/help/matlab/ref/fft.html?searchHighlight=fft&s_tid=doc_srchtitle 视 ...

  9. FFT 快速傅里叶变换 初探

    一直认为很高深的东西其实也并不很难. 以下内容部分来自qy大神的ppt,同时结合了自己的理解.但理解还不是很深,需要继续研究. 开头 首先什么是傅里叶变换:傅立叶变换能将满足一定条件的某个函数表示成三 ...

  10. FFT快速傅里叶变换详解

    介绍 简而言之,这个东西用来做多项式乘法. 比如说,有两个多项式: 3x2+2x+1,2x2+x+43x^2+2x+1~,~2x^2+x+4 3x2+2x+1 , 2x2+x+4 那么他们乘起来就是 ...

最新文章

  1. 预计2024年之前载人登月!NASA授予马斯克贝索斯公司大单
  2. 转 Hystrix入门指南 Introduction
  3. html导航条置顶,jquery导航菜单栏固定悬浮顶部实现效果
  4. android tls1.2用法,如何添加特定TLSv1.2工作CipherSuits与OkHttp支持 - Android 4.4的奇巧(API 19)...
  5. Flask--WebSocket
  6. 如何:创建公钥/私钥对
  7. 算法与数据结构题目汇总
  8. 操作技巧:在Python Shell里如何清屏
  9. spring mvc和swagger整合
  10. Rust : channel、多线程与 CTP相关机制的模拟
  11. 关于Android项目隐藏标题栏的方法总结
  12. 热电偶测温方案 AD7124+Pt100冷端补偿
  13. lgg7刷机包下载_LGG7One刷机包
  14. 【Ubuntu】安装H.264解码器
  15. wps中的word删除空白页
  16. 基于注意力对抗生成网络的AlphaFold从氨基酸序列建立三维蛋白质结构
  17. 北京科技大学C语言锐格答案,北京科技大学软件课程设计作业.pdf
  18. Web编程入门暨个人网站计划:Web前端开发入门
  19. Mr. Kitayuta vs. Bamboos
  20. 机器学习深版11:HMM模型

热门文章

  1. Linux perlbrew Perl5 安装教程
  2. Dynamics CRM调用选择用户弹窗
  3. 高速公路联网收费二义性路径识别系统原理及开发
  4. iOS weak关键字实现原理
  5. linux查找外接摄像头端口
  6. linux查看xlsm文件,XLSM 文件扩展名: 它是什么以及如何打开它?
  7. English Study
  8. Ken Thompson 的经典 C 程序
  9. 微信自动回复的智能聊天机器人怎么做?
  10. doom3灯光编辑器和FX编辑器