HDU 4609 3-idiots三个智障 FFT+组合计数
Posted legend_PawN
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDU 4609 3-idiots三个智障 FFT+组合计数相关的知识,希望对你有一定的参考价值。
HDU4609
这道三个智障的题目把我做成了智障,先膜拜bin神,他的题解已经很详细
Bin神的HDU4609题解
这里稍作一些解释:
num[i]
数组记录的不同长度的strick的个数,
num[i]∗num[i]
后代表任意可重复地那两根构成的长度的种类数
,题目要求是不可重复的,所以要进行第一次去重
之后考虑
num[i]
的前缀和数组
sum[i]
是为了对三角形的最大边进行枚举,我们知道三条线段构成三角形的充分必要条件是,两个较小的边
a
,
所以,前缀和数组
sum[i]
记录的是两边之和大于
i
的组合个数,那么
第二次去重,我们默认的
a[i]
是当前构成三角形的最大边,但是
sum[len]−sum[a[i]]
中包含了一下三种情况不满足条件需要去掉:假设另外两条边分别为
x1
与
x2
1.
x2>a[i],x1<a[i]
个数为
i×(n−1−i)
2.
x2=a[i]或者x1=a[i]
个数为
n−1
3.
x2>a[i],x1>a[i]
个数为
(n−i−1)×(n−i−2)2
这就是第二次去重,最后就能够得到答案
RuntimeError:注意
sum[i],num[i]
都要开成 long long,因为卷积后的数据超过了
109
。
AC代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const double PI=acos(-1);
int a[300005],n,len;
ll num[300005],sum[300005];
struct Complex
double r,i;
Complex()
Complex(double _r ,double _i )
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 rader(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)
rader(y,len);
for(int h=2;h<=len;h=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;
void convert(Complex a[],int len)
fft(a,len,1);
for(int i=0;i<len;i++)
a[i]=a[i]*a[i];
fft(a,len,-1);
Complex x1[300005],x2[300005];
int main()
//freopen("input.txt","r",stdin);
int T;
scanf("%d",&T);
while(T--)
memset(num,0,sizeof(num));
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
num[a[i]]++;
sort(a,a+n);
len=1;
while(len<2*(a[n-1]+1))
len=len<<1;
for(int i=0;i<a[n-1]+1;i++)
x1[i]=Complex(num[i],0);
for(int i=a[n-1]+1;i<len;i++)
x1[i]=Complex(0,0);
convert(x1,len);
for(int i=0;i<len;i++)
num[i]=ll(x1[i].r+0.5);
for(int i=0;i<n;i++)
num[a[i]+a[i]]--;
//for(int i=0;i<len;i++)
// printf("%lld ",num[i]);
//cout<<endl;
for(int i=0;i<len;i++)
num[i]=num[i]>>1;
for(int i=1;i<=len;i++) //预处理前缀和
sum[i]=sum[i-1]+num[i];
ll tot,ans=0;
tot=1LL*n*(n-1)*(n-2)/6;
for(int i=0;i<n;i++) //去重
ans+=sum[len]-sum[a[i]];
ans-=1LL*(n-1-i)*i;
ans-=1ll*(n-1);
ans-=1LL*(n-1-i)*(n-2-i)/2;
printf("%.7lf\\n",(double)ans/tot);
以上是关于HDU 4609 3-idiots三个智障 FFT+组合计数的主要内容,如果未能解决你的问题,请参考以下文章