题外话:好久没写blog了啊~~

题目传送门

题目大意:给你m条长度为ai的线段,求在其中任选三条出来,能构成三角形的概率。即求在这n条线段中找出三条线段所能拼出的三角形数量除以$\binom{m}{3}$。

假设我们手中有3条长度分别为$x,y,z$的边(为了简化问题我们假设$x<y<z$,$x,y,z$相等的情况另行讨论),如果他们能拼成三角形,必然满足$x+y>z$且$z-y<x$。

该题的$O(m^3)$做法:枚举其中的3条边,套用上面的判断公式,进行累计。

但通过简单的变式,我们假设我们已经确定了$x$和$y$,那么$z$的范围即为$[y,x+y)$,我们维护一个数组$num$,$num_i$表示长度为i的线段数量。再维护一个num的前缀和sum。则$ans=\sum^{n-1}_{x=1}  \sum^{n}_{y=x+1} num_x * num_y*(sum[x+y-1]-sum[y])$,运算该和式的时间复杂度为$O(n^2)$,此处的n表示最长线段的长度。

然而还是会TLE。。。。

我们考虑对其做一些变式。

$ans=\sum^{n-1}_{x=1}  \sum^{n}_{y=x+1} num_x * num_y*(sum[x+y-1]-sum[y])$

$=\sum^{n-1}_{x=1}  \sum^{n}_{y=x+1} num_x * num_y*sum[x+y-1] -\sum^{n-1}_{x=1}  \sum^{n}_{y=x+1} num_x * num_y*sum[y]$

该式子的后半部分,我们可以通过维护$num_y*sum[y]$的后缀和,实现O(n)的计算。

下面我们继续对式子的前半部分变式。令t=x+y。则有

$=\frac{1}{2}\sum^{2n}_{t=2}  \sum^{t-1}_{p=1} num_p*num_{t-p}*sum[t-1] -\frac{1}{2}\sum^{n}_{i=1}num_i^2*sum[2*i-1]$

我们发现,该式子的$\sum_{p=1}^{t-1} num_{p}\times num_{t-p}$,可以用FFT求出。则时间复杂度成功降低至O(n log n),而式子的后半部分可以O(n)求出,求和时间复杂度降低至O(n log n)。

下面说下x=y=z,x=y<z,x<y=z的处理方法。

x=y=z:$\sum _{\forall num_x>2} \binom{num_x}{3}$

x=y<z: $\sum _{x=1}^{n} \binom{num_x}{2}*(sum[2x-1]-sum[x])$

x<y=z:$\sum_{x=1}^{n}(sumc2_n-sumc2_x)$ ,其中$sumc2_x$ 表示$\sum_{i=1}^{x}\binom{num_x}{2}$。

把这三种情况和最初描述的情况相加即可。

 #include<bits/stdc++.h>
#define M 270000
#define cp complex<double>
#define PI acos(-1)
#define L long long
using namespace std;
cp a[M];
void change(cp a[],int len){
for(int i=,j=;i<len-;i++){
if(i<j) swap(a[i],a[j]);
int k=len>>;
while(j>=k) j-=k,k>>=;
j+=k;
}
}
void fft(cp a[],int n,int on){
change(a,n); cp t,u;
for(int h=;h<=n;h<<=){
cp wn(cos(-on**PI/h),sin(-on**PI/h));
for(int j=;j<n;j+=h){
cp w(,);
for(int k=j;k<j+(h>>);k++){
u=a[k]; t=w*a[k+(h>>)];
a[k]=u+t; a[k+(h>>)]=u-t;
w=w*wn;
}
}
}
}
L num[M]={},sum[M]={},sumhh[M]={},sumc2[M]={},sc[M]={},ans=; int Main(){
int m,n,maxn=; scanf("%d",&n);
for(int i=;i<=n;i++){
int x; scanf("%d",&x);
num[x]++; maxn=max(maxn,x);
}
for(m=;m<(maxn*+);m<<=);
for(int i=;i<m;i++) a[i]=cp(num[i],);
fft(a,m,);
for(int i=;i<m;i++) a[i]=a[i]*a[i];
fft(a,m,-);
for(int i=;i<m;i++) sc[i]=(a[i+].real()+0.5)/m;
for(int i=;i<m;i++){
sum[i]=sum[i-]+num[i];
sumc2[i]=sumc2[i-]+num[i]*(num[i]-)/;
} L ans1=,ans2=,ans3=,ans4=;
for(int i=;i<=maxn;i++) if(num[i]>)
ans1+=(L)num[i]*(num[i]-)*(num[i]-);
ans1/=;//x=y=z
for(int i=;i<=maxn;i++)
ans2+=(L)num[i]*(num[i]-)*(sum[*i-]-sum[i]);
ans2/=;//x=y<z
for(int i=;i<=maxn;i++)
ans3+=num[i]*(sumc2[maxn]-sumc2[i]);
//x<y=z
for(int i=;i<*maxn;i++) ans4+=sum[i]*sc[i];
for(int i=;i<=maxn;i++) ans4-=num[i]*num[i]*sum[*i-];
ans4/=;//x<y<z卷积部分 for(int i=maxn;i;i--) sumhh[i]=sumhh[i+]+num[i]*sum[i];
for(int i=;i<maxn;i++) ans4-=num[i]*sumhh[i+];
ans=ans1+ans2+ans3+ans4; double fenmu=(L)n*(n-)*(n-)/;
double hh=ans/fenmu;
printf("%.7lf\n",hh);
}
int main(){
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int cas; scanf("%d",&cas);
while(cas--){
memset(num,,sizeof(num)); memset(sum,,sizeof(sum));
memset(sumhh,,sizeof(sumhh)); memset(sumc2,,sizeof(sumc2));
memset(sc,,sizeof(sc)); memset(a,,sizeof(a)); ans=;
Main();
}
}

【hdu4609】 3-idiots FFT的更多相关文章

  1. 【bzoj3513】[MUTC2013]idiots FFT

    题目描述 给定n个长度分别为a_i的木棒,问随机选择3个木棒能够拼成三角形的概率. 输入 第一行T(T<=100),表示数据组数. 接下来若干行描述T组数据,每组数据第一行是n,接下来一行有n个 ...

  2. 【BZOJ3160】万径人踪灭(FFT,Manacher)

    [BZOJ3160]万径人踪灭(FFT,Manacher) 题面 BZOJ 题解 很容易想到就是满足条件的子序列个数减去回文子串的个数吧... 至于满足条件的子序列 我们可以依次枚举对称轴 如果知道关 ...

  3. 【BZOJ3527】力(FFT)

    [BZOJ3527]力(FFT) 题面 Description 给出n个数qi,给出Fj的定义如下: \[Fj=\sum_{i<j}\frac{q_i q_j}{(i-j)^2 }-\sum_{ ...

  4. 【BZOJ4827】【HNOI2017】礼物(FFT)

    [BZOJ4827][HNOI2017]礼物(FFT) 题面 Description 我的室友最近喜欢上了一个可爱的小女生.马上就要到她的生日了,他决定买一对情侣手 环,一个留给自己,一 个送给她.每 ...

  5. 【Matlab】快速傅里叶变换/ FFT/ fftshift/ fftshift(fft(fftshift(s)))

    [自我理解] fft:可以指定点数的快速傅里叶变换 fftshift:将零频点移到频谱的中间 用法: Y=fftshift(X) Y=fftshift(X,dim) 描述:fftshift移动零频点到 ...

  6. 【BZOJ】3160: 万径人踪灭 FFT+回文串

    [题意]给定只含'a'和'b'字符串S,求不全连续的回文子序列数.n<=10^5. [算法]FFT+回文串 [题解]不全连续的回文子序列数=回文子序列总数-回文子串数. 回文子串数可以用回文串算 ...

  7. 【BZOJ4624】农场种植 FFT

    [BZOJ4624]农场种植 Description 农夫约翰想要在一片巨大的土地上建造一个新的农场. 这块土地被抽象为个 R*C 的矩阵.土地中的每个方格都可以用来生产一种食物:谷物(G)或者是牲畜 ...

  8. 【BZOJ3160】万径人踪灭 Manacher+FFT

    [BZOJ3160]万径人踪灭 Description Input Output Sample Input Sample Output HINT 题解:自己想出来1A,先撒花~(其实FFT部分挺裸的) ...

  9. 【BZOJ3771】Triple 生成函数+FFT

    [BZOJ3771]Triple Description 我们讲一个悲伤的故事. 从前有一个贫穷的樵夫在河边砍柴. 这时候河里出现了一个水神,夺过了他的斧头,说: “这把斧头,是不是你的?” 樵夫一看 ...

随机推荐

  1. JavaScript的异步运行机制

    ----异步运行机制如下: 1.左右同步任务都在主线程上执行,形成一个执行栈 2.主线程值外,还存在一个任务队列,只要异步任务有了运行结果,就在任务队列中放置一个事件 3.一旦执行栈中的所有同步任务执 ...

  2. php 事务处理,ActiveMQ的发送消息,与处理消息

    可以通过链式发送->处理->发送...的方式处理类似事务型业务逻辑 比如 发送一个注册消息,消息队列处理完注册以后,紧接着发送一个新手优惠券赠送,赠送完再发一个其它后续逻辑处理的消息等待后 ...

  3. win 控制台工作路径切换

    1.如果是同磁盘 直接cd 列如cd C:\mysql\bin 2.如果不是同一磁盘 则要2.1 d: 操作 2.2 cd D:\Software\xampp\address\mysql\bin ps ...

  4. 《Linux多线程服务端编程——使用muduo C++网络库》读书笔记

    第一章 线程安全的对象生命期管理 第二章 线程同步精要 第三章 多线程服务器的适用场合与常用编程模型 第四章 C++多线程系统编程精要 1.(P84)11个常用的最基本Pthreads函数: 2个:线 ...

  5. Wireshark数据包分析(一)——使用入门

    Wireshark简介: Wireshark是一款最流行和强大的开源数据包抓包与分析工具,没有之一.在SecTools安全社区里颇受欢迎,曾一度超越Metasploit.Nessus.Aircrack ...

  6. fastreport字体加粗

    procedure MasterData1OnBeforePrint(Sender: TfrxComponent); begin IF (<frxDB_cdsresult."res_C ...

  7. 项目笔记---事半功倍之StyleCop(一)

    前言 曾几何时,你是否在看别人代码的时候总是在抱怨代码没有注释,命名不规范,代码风格不统一,代码可读性差?是否有一个适合团队开发规范的检查工具? 答案就是大名鼎鼎的StyleCop代码检查插件,有了这 ...

  8. asp.net core mvc 管道之中间件

    asp.net core mvc 管道之中间件 http请求处理管道通过注册中间件来实现各种功能,松耦合并且很灵活 此文简单介绍asp.net core mvc中间件的注册以及运行过程 通过理解中间件 ...

  9. WebService 工作原理及实例教程

    一.WebService到底是什么? 先来看下标准的定义:Web Service也叫XML Web Service WebService是一种可以接收从Internet或者Intranet上的其它系统 ...

  10. [.net 多线程]线程基础

    一.线程状态 1.新建状态(New):         当用new操作符创建一个线程时, 例如new Thread(r),线程还没有开始运行,此时线程处在新建状态. 当一个线程处于新生状态时,程序还没 ...