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

总思路是先选两条边,把两条边的所有情况列出来

再枚举第三条边

排个序,设第三条边最小,容斥一下,

两个数列的元素的相加可以看成是生成函数

生成函数又是个多项式

多项式求卷积

3-idiots

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 216    Accepted Submission(s): 73

Problem Description

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.

Input

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

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

Sample Input

2 4 1 3 3 4 4 2 3 3 4

Sample Output

0.5000000 1.0000000

Source

2013 Multi-University Training Contest 1

Recommend

liuyiding

学会了FFT。

这题就很容易了。

其实题目是给了n条线段。问随机取三个,可以组成三角形的概率。

其实就是要求n条线段,选3条组成三角形的选法有多少种。

首先题目给了a数组,

如样例一:

4

1 3 3 4

把这个数组转化成num数组,num[i]表示长度为i的有num[i]条。

样例一就是

num = {0   1   0    2    1}

代表长度0的有0根,长度为1的有1根,长度为2的有0根,长度为3的有两根,长度为4的有1根。

使用FFT解决的问题就是num数组和num数组卷积。

num数组和num数组卷积的解决,其实就是从{1 3 3 4}取一个数,从{1 3 3 4}再取一个数,他们的和每个值各有多少个

例如{0 1 0 2 1}*{0 1 0 2 1} 卷积的结果应该是{0 0  1  0  4  2  4  4  1 }

长度为n的数组和长度为m的数组卷积,结果是长度为n+m-1的数组。

{0 1 0 2 1}*{0 1 0 2 1} 卷积的结果应该是{0 0  1  0  4  2  4  4  1 }。

这个结果的意义如下:

从{1 3 3 4}取一个数,从{1 3 3 4}再取一个数

取两个数和为 2 的取法是一种:1+1

和为 4 的取法有四种:1+3, 1+3  ,3+1 ,3+1

和为 5 的取法有两种:1+4 ,4+1;

和为 6的取法有四种:3+3,3+3,3+3,3+3,3+3

和为 7 的取法有四种: 3+4,3+4,4+3,4+3

和为 8 的取法有 一种:4+4

利用FFT可以快速求取循环卷积,具体求解过程不解释了,就是DFT和FFT的基本理论了。

总之FFT就是快速求到了num和num卷积的结果。只要长度满足>=n+m+1.那么就可以用循环卷积得到线性卷积了。

弄完FFT得到一个num数组,这个数组的含义在上面解释过了。

        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);fft(x1,len,1);for(int i = 0;i < len;i++)x1[i] = x1[i]*x1[i];fft(x1,len,-1);for(int i = 0;i < len;i++)num[i] = (long long)(x1[i].r+0.5);

这里代码中的num数组就是卷积后的结果,表示两两组合。

但是题目中本身和本身组合是不行的,所有把取同一个的组合的情况删掉。

        //减掉取两个相同的组合for(int i = 0;i < n;i++)num[a[i]+a[i]]--;

还有,这个问题求组合,所以第一个选t1,第二个选t2,和第一个选t2,第二个选t1,我们认为是一样的。

所有num数组整体除于2

        //选择的无序,除以2for(int i = 1;i <= len;i++){num[i]/=2;}

然后对num数组求前缀和

        sum[0] = 0;for(int i = 1;i <= len;i++)sum[i] = sum[i-1]+num[i];

之后就开始O(n)找可以形成三角形的组合了。

a数组从小到大排好序。

对于a[i].  我们假设a[i]是形成的三角形中最长的。这样就是在其余中选择两个和>a[i],而且长度不能大于a[i]的。(注意这里所谓的大于小于,不是说长度的大于小于,其实是排好序以后的,位置关系,这样就可以不用管长度相等的情况,排在a[i]前的就是小于的,后面的就是大于的)。

根据前面求得的结果。

长度和大于a[i]的取两个的取法是sum[len]-sum[a[i]].

但是这里面有不符合的。

一个是包含了取一大一小的

cnt -= (long long)(n-1-i)*i;

一个是包含了取一个本身i,然后取其它的

cnt -= (n-1);

还有就是取两个都大于的了

cnt -= (long long)(n-1-i)*(n-i-2)/2;

这样把i从0~n-1累加,就答案了。

        long long cnt = 0;for(int i = 0;i < n;i++){cnt += sum[len]-sum[a[i]];//减掉一个取大,一个取小的cnt -= (long long)(n-1-i)*i;//减掉一个取本身,另外一个取其它cnt -= (n-1);//减掉大于它的取两个的组合cnt -= (long long)(n-1-i)*(n-i-2)/2;}

使用FFT一定要注意控制好长度,长度要为2^k.而且大于等于len1+len2-1.这样可以保证不重叠。

然后就是用long long,有的地方会超int的。

#include <stdio.h>
#include <iostream>
#include <string.h>
#include <algorithm>
#include <math.h>
using namespace std;const double PI = acos(-1.0);
struct complex
{double r,i;complex(double _r = 0,double _i = 0){r = _r; i = _i;}complex operator +(const complex &b){return complex(r+b.r,i+b.i);}complex operator -(const complex &b){return complex(r-b.r,i-b.i);}complex operator *(const complex &b){return complex(r*b.r-i*b.i,r*b.i+i*b.r);}
};
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 /= 2;}if(j < k)j += k;}
}
void fft(complex y[],int len,int on)
{change(y,len);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].r /= len;
}const int MAXN = 400040;
complex x1[MAXN];
int a[MAXN/4];
long long num[MAXN];//100000*100000会超int
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]]++;}sort(a,a+n);int len1 = a[n-1]+1;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);fft(x1,len,1);for(int i = 0;i < len;i++)x1[i] = x1[i]*x1[i];fft(x1,len,-1);for(int i = 0;i < len;i++)num[i] = (long long)(x1[i].r+0.5);len = 2*a[n-1];//减掉取两个相同的组合for(int i = 0;i < n;i++)num[a[i]+a[i]]--;//选择的无序,除以2for(int i = 1;i <= len;i++){num[i]/=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]];//减掉一个取大,一个取小的cnt -= (long long)(n-1-i)*i;//减掉一个取本身,另外一个取其它cnt -= (n-1);//减掉大于它的取两个的组合cnt -= (long long)(n-1-i)*(n-i-2)/2;}//总数long long tot = (long long)n*(n-1)*(n-2)/6;printf("%.7lf\n",(double)cnt/tot);}return 0;
}

自己的奇丑代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <math.h>
#include <memory.h>
#include <bits/stdc++.h>
using namespace std;
#define LL long long
typedef pair<int,int> pii;
const LL inf = 0x3f3f3f3f;
const LL MOD =100000000LL;
const int maxn = 400010;
const double eps = 1e-8;
void fre() {freopen("in.txt","r",stdin);}
void freout() {freopen("out.txt","w",stdout);}
inline int read() {int x=0,f=1;char ch=getchar();while(ch>'9'||ch<'0') {if(ch=='-') f=-1; ch=getchar();}while(ch>='0'&&ch<='9') {x=x*10+ch-'0';ch=getchar();}return x*f;}const double PI = acos(-1.0);
//复数结构体
struct Complex{double r,i;Complex(double _r = 0.0,double _i = 0.0){r = _r; i = _i;}Complex operator +(const Complex &b){return Complex(r+b.r,i+b.i);}Complex operator -(const Complex &b){return Complex(r-b.r,i-b.i);}Complex operator *(const Complex &b){return Complex(r*b.r-i*b.i,r*b.i+i*b.r);}
};
/** 进行FFT和IFFT前的反转变换。* 位置i和 (i二进制反转后位置)互换* len必须去2的幂*/
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]);//交换互为小标反转的元素,i<j保证交换一次//i做正常的+1,j左反转类型的+1,始终保持i和j是反转的k = len/2;while( j >= k){j -= k;k /= 2;}if(j < k) j += k;}
}
/** 做FFT* len必须为2^k形式,* on==1时是DFT,on==-1时是IDFT*/
void fft(Complex y[],int len,int on){change(y,len);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].r /= len;
}
Complex a[maxn];
Complex b[maxn];
long long ans[maxn];
int num[maxn];
int p[maxn];
long long sum[maxn];
int main()
{int t;scanf("%d",&t);while(t--){int n;scanf("%d",&n);int x;memset(num,0,sizeof(num));memset(sum,0,sizeof(sum));memset(ans,0,sizeof(ans));memset(p,0,sizeof(p));for(int i=0;i<n;i++){scanf("%d",&p[i]);num[p[i]]++;}sort(p,p+n);int len=1;while(len<2*p[n-1]+1)//最大p[n-1]{len<<=1;}for(int i=0;i<len;i++){a[i]=Complex(num[i],0);}fft(a,len,1);for(int i=0;i<len;i++){a[i]=a[i]*a[i];}fft(a,len,-1);for(int i=0;i<len;i++){ans[i]=(long long)(a[i].r+0.5);}for(int i=0;i<n;i++)ans[p[i]*2]--;for(int i=0;i<len;i++)ans[i]>>=1;long long res=0;sum[0]=0;for(int i=1;i<len;i++){sum[i]=sum[i-1]+ans[i];}for(int i=0;i<n;i++)//设p[i]是最小的边{res+=sum[len-1]-sum[p[i]];res-=(long long)(n-i-1)*i;res-=(n-1);res-=(long long)(n-1-i)*(n-i-2)/2;}/*printf("**********\n");for(int i=0;i<len;i++){printf("%d %lld\n",i,ans[i]);}*/long long tot=(long long)n*(n-1)*(n-2)/6;//总Cn3printf("%.7f\n",(double)res/tot);}
}

HDU 4609 3-idiots (思维+FFT卷积)相关推荐

  1. hdu 4609 3-idiots(FFT计数)

    题目链接:hdu 4609 3-idiots 题意: 给你n条线段.问随机取三个,可以组成三角形的概率. 题解: FFT搞,具体可看kuangbin菊苣的详细题解:传送门 1 #include< ...

  2. HDU 4609 3-idiots

    HDU - 4609 思路: 记录每个木棍长度出现的次数,然后就可以用用类似多项式的乘法(专业术语:卷积,因为是下标和为一特定值的积的和(x+y=k),相当于在笛卡尔坐标系中将这条直线卷起来,故得名卷 ...

  3. 快速傅里叶变换应用之二 hdu 4609 3-idiots

    快速傅里叶变化有不同的应用场景,hdu4609就比较有意思.题目要求是给n个线段,随机从中选取三个,组成三角形的概率. 初始实在没发现这个怎么和FFT联系起来,后来看了下别人的题解才突然想起来:组合计 ...

  4. BZOJ_2194_快速傅立叶之二_(FFT+卷积)

    描述 http://www.lydsy.com/JudgeOnline/problem.php?id=2194 给出序列\(a[0],a[1],...,a[n-1]\)和\(b[0],b[1],... ...

  5. HDU 4609 3-idiots FFT

    3-idiots 题目连接: http://acm.hdu.edu.cn/showproblem.php?pid=4609 Description King OMeGa catched three m ...

  6. HDU 4609 3-idiots(FFT)

    3-idiots 思路 多项式卷积的经典应用了: 看样例一: 4 1 3 3 4 我们用多项式系数表示得到一个与aia_iai​有关的多项式:010210\ 1\ 0\ 2\ 10 1 0 2 1, ...

  7. HDU 4609 FFT

    题目大意 给定n条边的边值,求任意取三条边能组成三角形的概率 这里概率 P = valid/tot tot = (n-2)*(n-1)*n/6是没问题的 valid表示合法的方式 先考虑,任意两条边组 ...

  8. 3-idiots HDU - 4609 FFT模板

    给N个木棍问任选三个可组合出三角形的概率 以前写的,整理整理存个档 //#pragma comment(linker, "/STACK:1024000000,1024000000" ...

  9. 【BZOJ】3527: [Zjoi2014]力(fft+卷积)

    http://www.lydsy.com/JudgeOnline/problem.php?id=3527 好好的一道模板题,我自己被自己坑了好久.. 首先题目看错.......什么玩意.......首 ...

  10. 2021牛客多校1 - Hash Function(思维+FFT)

    题目链接:点击查看 题目大意:给出一个长度为 nnn 的序列,现在要求找到一个 seedseedseed,使得所有数字变为 a[i]=a[i]modseeda[i]=a[i]\mod seeda[i] ...

最新文章

  1. 成功解决tensorflow\contrib\learn\python\learn\datasets\base._internal_retry.locals.wrap.locals.wrapp
  2. Splay(单点修改+查询)
  3. 通过取父级for循环的i来理解闭包,iife,匿名函数
  4. c语言if的时候自动转换,[求助]IF语句转换SWITCH语句写出!如何
  5. 追加画面文言时注意【×硬换行】与【○软换行】
  6. lvm硬盘管理及LVM扩容
  7. html中出现的script失效
  8. matlab exprnd函数,Matlab 用 exprnd 函数生成符合指数分布的随机数
  9. win98装python_Windows 上的 Python安装
  10. Java毕设项目银行贷款管理系统计算机(附源码+系统+数据库+LW)
  11. 软件测试报告模板--实用--绝对靠谱
  12. 吉他即兴Solo演奏训练教程
  13. C++实现经典同步问题(生产者消费者、读者写者、哲学家进餐、吸烟者问题)
  14. CentOS7安装oh-my-zsh(github start Top 10)
  15. 2022年第七届IEEE云计算与大数据分析国际会议
  16. jsp:使用jsp完成数据的分页显示
  17. 文件排版(文本文件读写)
  18. 出差中,推荐几个百度,腾讯,抖音大佬的公众号
  19. 连接服务器显示凭据,连接云服务器时的凭据是什么意思
  20. HihoCoder - 1847

热门文章

  1. win7计算机盘共享,win7电脑如何共享文件夹 win7电脑共享文件夹操作方法
  2. Liunx 安装 phpStudy
  3. juniper防火墙开启NAT功能
  4. wdcp虚拟主机管理系统注入漏洞
  5. 阿里云centos7系统下载
  6. 信息服务器在哪里打开,internet信息服务(lls)管理器在哪里打开
  7. 在html中加入网址,网页超链接怎么做,添加超链接网址的的详细步骤
  8. iOS动画之大雪纷飞
  9. 程序员之路:Gmail邮箱客户端配置_彭世瑜_新浪博客
  10. 关于微信授权获取昵称含Emoji表情引发的乱码问题总结