hdu 4609

来源:互联网 发布:java并发编程应用在哪 编辑:程序博客网 时间:2024/05/29 12:18

题目描述:

1e5个长度1e5以内的棍子,随便挑出3根不同的(长度可以相同)的棍,问组成三角形的概率

题解:

主要分两块:(1)fft可以快速算出两个棍子和是多少和几个的情况.通过减去单个的和/2后续处理可以得到.(2)有了a+b,并没有a-b.于是思维转换,不对a+b挑c,而是枚举c找a+b.并且定义枚举的c是最大的(这里的最大,如果一样,则标号最大,只是为了不统计重复).这样巧妙地把a-b

重点:

关键是第二个思路的转换

代码:

#include <iostream>#include <cstdio>#include <cstring>#include <string>#include <cmath>#include <ctype.h>#include <limits.h>#include <cstdlib>#include <algorithm>#include <vector>#include <queue>#include <map>#include <stack>#include <set>#include <bitset>#define CLR(a) memset(a, 0, sizeof(a))#define REP(i, a, b) for(ll i = a;i < b;i++)#define REP_D(i, a, b) for(ll i = a;i <= b;i++)typedef long long ll;using namespace std;const double PI = acos(-1.0);const ll maxn = 5e5 + 100;ll num[maxn], a[maxn];ll sum[maxn];ll n, len, num_n;//复数结构体struct Complex{    double x,y;//实部和虚部 x+yi    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);    }};Complex x1[maxn],x2[maxn];/** 进行FFT和IFFT前的反转变换。* 位置i和 (i二进制反转后位置)互换* len必须去2的幂*/void change(Complex y[],ll len){    ll 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[],ll len,ll on){    change(y,len);    for(ll h = 2; h <= len; h <<= 1)    {        Complex wn(cos(-on*2*PI/h),sin(-on*2*PI/h));        for(ll j = 0; j < len; j+=h)        {            Complex w(1,0);            for(ll 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(ll i = 0; i < len; i++)            y[i].x /= len;}void doFFT(ll a[], ll &len){    ll len1 = 1;    while(len1 < 2*len)    {        len1*=2;    }    for(ll i=0;i<len;i++)    {        x1[i] = Complex(a[i], 0);    }    for(ll i=len;i<len1;i++)    {        x1[i] = Complex(0, 0);    }    fft(x1, len1, 1);    for(ll i=0;i < len1;i++)    {        x1[i] = x1[i]*x1[i];    }    fft(x1, len1, -1);    len=len1;    for(ll i=0;i < len;i++)    {        a[i] = (ll)(x1[i].x+0.5);    }}ll select(ll x){    if(x==0)        return 0;    if(x==1)        return 0;    return x*(x-1)/2;}void solve(){    sort(a, a+n);    len = a[n-1]+1;    num_n = len;    CLR(num);    REP(i, 0, n)    {        num[a[i]]++;    }    //fft    doFFT(num, num_n);    REP(i, 0, n)    {        num[a[i]+a[i]]--;    }    REP(i, 0, num_n)    {//        if(num[i]%2!=0)//            printf("dfasdfasd");        num[i] /= 2;    }    //printf("%I64d\n", num_n);    sum[0]=0;    REP(i, 1, num_n)    {        sum[i]=sum[i-1]+num[i];    }    ll ans=0;    REP(i, 0, n)    {        ans += (sum[num_n-1] - sum[a[i]]);        ans -= (n-1);        ans -= select(n-i-1);        ans -= (n-i-1)*i;    }    ll tot = n*(n-1)*(n-2)/6;    double res = ans*1.0/(double)tot;    printf("%.7f\n", res);}int main(){    //freopen("3Cin.txt", "r", stdin);    //freopen("3Cout.txt", "w", stdout);    ll t;    scanf("%I64d", &t);    while(t--)    {        scanf("%I64d", &n);        REP(i, 0, n)        {            scanf("%I64d", &a[i]);        }        solve();    }    return 0;}
0 0
原创粉丝点击