hdu 4609 3-idiots(FFT)

Posted jpphy0

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了hdu 4609 3-idiots(FFT)相关的知识,希望对你有一定的参考价值。

问题

hdu 4609 3-idiots - https://acm.hdu.edu.cn/showproblem.php?pid=4609

分析

  • fft 方法计算两边之和
  • 两边之和去重
    • 同一条边取两次,即 a + a = 2a
    • 两条边选取的次序交换,即 a + b = b + a,因此除2
  • 两边之和大于第3边,按第3边最大枚举第3边去重
    • 将n条边排序
    • 升序枚举各边,前缀和方式计算大于当前边的两边可取数
    • 以下三种情况因重复不符去除
      • 两条边均比当前边长,设当前边是第i条,则去除 ( n − i ) ∗ ( n − i − 1 ) / 2 (n-i)*(n-i-1)/2 (ni)(ni1)/2
      • 一条边不小于当前边,一条边不大于当前边,则去除 ( i − 1 ) ∗ ( n − i ) (i-1)*(n-i) (i1)(ni)
      • 当前边已被使用,则去除 n − 1 n-1 n1

代码

#include<bits/stdc++.h>
using namespace std;
#define LL long long
const double DFT = 2.0, IDFT = -2.0, PI = acos(-1);
const int MXN = 1e5+10, MXL = MXN << 2, MXV = MXN;
struct CP{
    double r, i;
    CP(double _r = 0, double _i = 0):r(_r), i(_i){};
    CP operator +(CP x){ return CP(r+x.r, i+x.i); }
    CP operator -(CP x){ return CP(r-x.r, i-x.i); }
    CP operator *(CP x){ return CP(r*x.r - i*x.i, r*x.i + i*x.r); }
    CP operator *=(CP x){ 
        double xr = x.r, xi = x.i, tr = r;
        r = r*xr - i*xi, i = tr*xi + i*xr;
        return *this;
    }
    void print(char pad){ printf("%d%c", (int)(r+0.5), pad); }
}p[MXL];
int n, r[MXL], d[MXN], cnt[MXV];
LL sum[MXV<<1], ans, tot;
void fft(CP p[], int len, double mode){
    for(int i = 0; i < len; ++i) if(i < r[i]) swap(p[i], p[r[i]]);
    for(int i = 2; i <= len; i <<= 1){
        CP wn(cos(mode*PI/i), sin(mode*PI/i));
        for(int j = 0; j < len; j += i){
            CP w(1.0, 0.0);
            for(int k = j; k < j+(i>>1); ++k, w *= wn){
                CP l = p[k], r = w*p[k+(i>>1)];
                p[k] = l + r, p[k+(i>>1)] = l - r;
            }
        }
    }
    if(mode == DFT) return;
    for(int i = 0; i <= len; ++i) p[i].r /= len;
}
int main(){
    int t, lim, bit, mx;
    scanf("%d", &t);
    while(t--){        
        memset(cnt, 0, sizeof cnt), memset(sum, 0, sizeof sum);
        p[0].r = 0, p[0].i = 0, mx = 0, ans = 0;
        scanf("%d", &n);
        for(int i = 1; i <= n; ++i) scanf("%d", d+i), mx = max(mx, d[i]), ++cnt[d[i]];
        for(int i = 1; i < MXV; ++i) p[i].r = cnt[i], p[i].i = 0;
        for(int i = MXV; i < MXL; ++i) p[i].r = 0, p[i].i = 0;
        lim = mx, bit = 2;
        while(lim >>= 1) ++bit;
        lim = 1 << bit;
        for(int i = 0; i < lim; ++i) r[i] = (r[i>>1]>>1)|((i&1)<<(bit-1));
        fft(p, lim, DFT);
        for(int i = 0; i <= lim; ++i) p[i] *= p[i];
        fft(p, lim, IDFT);
        for(int i = 1; i < MXV; ++i) if(cnt[i]) p[i<<1].r -= cnt[i]; // 同一个取两次去重
        for(int i = 0; i < (MXV<<1); ++i) p[i].r /= 2; // 不同的两个先后取去重
        for(int i = 1; i < (MXV<<1); ++i) sum[i] += sum[i-1] + (LL)(p[i].r+0.5);
        sort(d+1, d+n+1);
        for(int i = 1; i <= n; ++i){
            ans += sum[(mx<<1)+1] - sum[d[i]];
            ans -= 1LL*(i-1)*(n-i);
            ans -= n-1;
            ans -= 1LL*(n-i)*(n-i-1)/2;
        }
        tot = 1LL * n * (n - 1) * (n - 2) / 6;
        printf("%.7f\\n", 1.0*ans/tot);
    }
    return 0;
}
  • 两边之和小于等于第三边不构成三角形
  • 两边之差大于等于第三边不构成三角形
  • 但第二种情形总可以被第一种情形包含
#include<bits/stdc++.h>
using namespace std;
typedef complex<double> cd;
typedef long long ll;
const double DFT = 2.0, IDFT = -2.0, PI = acos(-1);
const int MXN = 1e5+10, MXL = MXN << 2, MXV = MXN;
cd p[MXL];
int n, r[MXL], c[MXV];
ll tmp, pre, tot, sum[MXV<<1];
void fft(cd p[], int len, double mode){
    for(int i = 0; i < len; ++i) if(i < r[i]) swap(p[i], p[r[i]]);
    for(int i = 2; i <= len; i <<= 1){
        cd wn(cos(mode*PI/i), sin(mode*PI/i));
        for(int j = 0; j < len; j += i){
            cd w(1.0, 0.0);
            for(int k = j; k < j+(i>>1); ++k, w *= wn){
                cd l = p[k], r = w*p[k+(i>>1)];
                p[k] = l + r, p[k+(i>>1)] = l - r;
            }
        }
    }
    if(mode == DFT) return;
    for(int i = 0; i <= len; ++i) p[i] /= len;
}
int main(){
    int t, lim, bit;    
    scanf("%d", &t);
    while(t--){        
        memset(c, 0, sizeof c), p[0] = 0, lim = 0;
        scanf("%d", &n);
        for(int x, i = 1; i <= n; ++i) scanf("%d", &x), lim = max(lim, x), ++c[x];
        for(int i = 1; i < MXV; ++i) p[i] = c[i];
        for(int i = MXV; i < MXL; ++i) p[i] = 0;
        bit = 2;
        while(lim >>= 1) ++bit;
        lim = 1 << bit;
        for(int i = 0; i < lim; ++i) r[i] = (r[i>>1]>>1)|((i&1)<<(bit-1));
        fft(p, lim, DFT);
        for(int i = 0; i <= lim; ++i) p[i] *= p[i];
        fft(p, lim, IDFT);
        for(int i = 1; i < MXV; ++i) if(c[i]) p[i<<1] -= c[i];
        for(int i = 0; i < (MXV<<1); ++i) sum[i] = (ll)(p[i].real()/2 +0.5);
        tmp = tot = 1LL * n * (n - 1) * (n - 2) / 6, pre = 0;
        for(int i = 0; i < MXV; ++i) pre += sum[i], tmp -= 1LL*pre*c[i]; 
        printf("%.7f\\n", 1.0*tmp/tot);
    }
    return 0;
}

以上是关于hdu 4609 3-idiots(FFT)的主要内容,如果未能解决你的问题,请参考以下文章

hdu 4609 3-idiots(FFT)

hdu 4609 3-idiots —— FFT

HDU 4609 3-idiots(FFT计数)

HDU4609 3-idiots(母函数 + FFT)

HDU 4609 3-idiots ——(FFT)

HDU 4609 3-idiots fft