zoukankan      html  css  js  c++  java
  • hdu4609(fft)

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4609

    题意: 给出 n 根木棒求从中任取三根可以组成三角形的概率.

    思路: fft

    将 a 数组转化为 num 数组, 其中 num[i] 为长度为 i 的木棒的数目, 再做 num 和 num 的卷积, 这步可以用 fft 模板完成. 将卷积结果存入 num 中, 则 num[i] 为从 n 根木棒中任选两根且其长度和为 i 的组合数. 注意: 里面包含了自己和自己组合以及正反序的情况. 所以要先对 num 处理一下.

    若两边的长和为 x (x > 0), 再有一条边长度小于 x 且大于 0, 那么这三条边一定可以组成三角形. 前面已经得到了 num 数组, 那么接下来可以枚举第三条边, 然后累计对答案的贡献. 为了避这里免重复计算, 先给 a 数组排序, 然后枚举 a[i] 作为当前三角形中的最长边, 累计对答案的贡献即可.

    得到了能组成三角形的方案数 sol, 则概率为 sol / (n * (n - 1) * (n - 2) / 6).

    代码:

      1 #include <iostream>
      2 #include <algorithm>
      3 #include <math.h>
      4 #include <string.h>
      5 #include <stdio.h>
      6 #define ll long long
      7 using namespace std;
      8 
      9 const double PI = acos(-1.0);
     10 
     11 struct Complex{//复数结构体
     12     double x, y;//实部,虚部
     13     Complex(double _x = 0.0, double _y = 0.0){
     14         x = _x;
     15         y = _y;
     16     }
     17     Complex operator -(const Complex &b) const{
     18         return Complex(x - b.x, y - b.y);
     19     }
     20     Complex operator +(const Complex &b) const{
     21         return Complex(x + b.x, y + b.y);
     22     }
     23     Complex operator *(const Complex &b) const{
     24         return Complex(x * b.x - y * b.y, x * b.y + y * b.x);
     25     }
     26 };
     27 
     28 //进行FFT和IFFT反转变化
     29 //位置i和(i二进制反转后位置)互换
     30 void change(Complex y[], int len){//len必须为2的幂
     31     for(int i = 1, j = len / 2; i < len - 1; i++){
     32         if(i < j) swap(y[i], y[j]); //交换互为下标反转的元素,i<j保证只交换一次
     33         int k = len >> 1;
     34         while(j >= k){
     35             j -= k;
     36             k /= 2;
     37         }
     38         if(j < k) j += k;
     39     }
     40 }
     41 
     42 //做FFT,len必须为2的幂,on=1是DFT,on=-1是IDTF
     43 void fft(Complex y[], int len, int on){
     44     change(y, len);//调用反转置换
     45     for(int h = 2; h <= len; h <<= 1){
     46         Complex wn(cos(-on * 2 * PI / h), sin(-on * 2 * PI / h));
     47         for(int j = 0; j < len; j += h){
     48             Complex w(1, 0);//初始化螺旋因子
     49             for(int k = j; k < j + h / 2; k++){//配对
     50                 Complex u = y[k];
     51                 Complex t = w * y[k + h / 2];
     52                 y[k] = u + t;
     53                 y[k + h / 2] = u - t;
     54                 w = w * wn;//更新螺旋因子
     55             }
     56         }
     57     }
     58     if(on == -1){
     59         for(int i = 0; i < len; i++){
     60             y[i].x /= len;//IDTF
     61         }
     62     }
     63 }
     64 
     65 const int MAXN = 4e5 + 10;
     66 ll sum[MAXN], num[MAXN];
     67 Complex x1[MAXN];
     68 int a[MAXN];
     69 
     70 int main(void){
     71     int t, n;
     72     scanf("%d", &t);
     73     while(t--){
     74         scanf("%d", &n);
     75         memset(num, 0, sizeof(num));
     76         memset(sum, 0, sizeof(sum));
     77         for(int i = 0; i < n; i++){
     78             scanf("%d", &a[i]);
     79             num[a[i]]++;
     80         }
     81         sort(a, a + n);
     82         int len = 1;
     83         int len1 = a[n - 1] + 1;
     84         while(len < (len1 << 1)) len <<= 1;
     85         for(int i = 0; i < len1; i++){
     86             x1[i] = Complex(num[i], 0);
     87         }
     88         for(int i = len1; i < len; i++){
     89             x1[i] = Complex(0, 0);
     90         }
     91         fft(x1, len, 1);
     92         for(int i = 0; i < len; i++){
     93             x1[i] = x1[i] * x1[i];
     94         }
     95         fft(x1, len, -1);//IDFT(x1*x1)
     96         for(int i = 0; i < len; i++){
     97             num[i] = (ll)(x1[i].x + 0.5);//四舍五入
     98         }
     99         //此时的num[i]为从a中选中任意两根木棒的和等于i的组合数,包含了自己和自己组合的情况以及正反序的组合情况
    100         ll sol = 0;
    101         len = a[n - 1] << 1;
    102         for(int i = 0; i < n; i++){//减去自己和自己组合的
    103             num[a[i] + a[i]]--;
    104         }
    105         for(int i = 0; i <= len; i++){//得到的组合数是无序的,所以要除2
    106             num[i] /= 2;
    107         }
    108         for(int i = 1; i <= len; i++){
    109             sum[i] += sum[i - 1] + num[i];//sum[i]即从n根木棍中选出两根长度和大于等于i的方案数
    110         }
    111         for(int i = 0; i < n; i++){//当a[i]为三角形最长边时对答案的贡献
    112             sol += sum[len] - sum[a[i]];
    113             sol -= (ll)(n - i - 1) * i;//减去有一条边大于a[i]的情况
    114             sol -= (ll)(n - i - 1) * (n - i - 2) / 2;//减去两条边都大于a[i]的情况
    115             sol -= n - 1;//减去包括a[i]的情况
    116         }
    117         ll cnt = (ll)n * (n - 1) * (n - 2) / 6;
    118         double gel = sol * 1.0 / cnt;
    119         printf("%.7lf
    ", gel);
    120     }
    121     return 0;
    122 }
    View Code
  • 相关阅读:
    IDEA快速搭建 SpringCloud 注册中心与
    -bash: nginx: 未找到命令 (command not found) 解决方案
    【转载】02-PowerDesigner的下载及安装
    redis.conf配置文件配置项解析
    Linux 重启防火墙失败
    hduoj 3459 Rubik 2×2×2
    sdutoj 2605 A^X mod P
    hduoj 4710 Balls Rearrangement 2013 ACM/ICPC Asia Regional Online —— Warmup
    hduoj 4708 Rotation Lock Puzzle 2013 ACM/ICPC Asia Regional Online —— Warmup
    hduoj 4715 Difference Between Primes 2013 ACM/ICPC Asia Regional Online —— Warmup
  • 原文地址:https://www.cnblogs.com/geloutingyu/p/7528191.html
Copyright © 2011-2022 走看看