• HDU 4609


    题意:

      给出一些木棍的长度, 问你随机三根组成三角形的概率

    分析:

      枚举最长边,求出所有其余两边之和大于最长边的数目

      将原来的长度点集 a[] 转化成某长度的数量点集 num[]

      并求出任意两根相加的值的数量点集 sum[]

      即 sum[m] = ∑num[i] * num[m - i] , 满足多项式相乘形式

      故用 FFT 优化

      然后 去掉 sum[] 中重复项 :

        1. num[i]取了两次

        2. num[i] * num[j] 与 num[j] * num[i] 重复

       枚举最长边时, 要保持剩下两条边都比他小的性质

      故要去掉不符项:

        1. sum[] 中包含该边

        2. 剩下两边中有一边大于该边

        3. 剩下两边都大于该边

      1 #include <iostream>
      2 #include <cstdio>
      3 #include <cstring>
      4 #include <cmath>
      5 #include <algorithm>
      6 using namespace std;
      7 #define LL long long
      8 const int MAXN = 1e5 + 5;
      9 const int MAXM = 4e5 + 5;
     10 const double PI = 4 * atan(1.0);
     11 
     12 struct Complex
     13 {
     14     double x,y;
     15     Complex(double xx = 0.0,double yy = 0.0): x(xx), y(yy) {}
     16     Complex operator - (const Complex &b) const
     17     {
     18         return Complex(x - b.x, y - b.y);
     19     }
     20     Complex operator + (const Complex &b) const
     21     {
     22         return Complex(x + b.x, y + b.y);
     23     }
     24     Complex operator * (const Complex &b) const
     25     {
     26         return Complex(x*b.x - y*b.y, x*b.y + y*b.x);
     27     }
     28 };
     29 void Change(Complex y[], int len)
     30 {
     31     int i, j, k;
     32     for (i = 1, j = len/2; i < len-1; i++)
     33     {
     34         if (i < j) swap(y[i], y[j]);
     35         k = len/2;
     36         while (j >= k)
     37         {
     38             j -= k;
     39             k /= 2;
     40         }
     41         if (j < k) j += k;
     42     }
     43 }
     44 void FFT(Complex y[], int len, int on)
     45 {
     46     Change(y, len);
     47     for (int h = 2; h <= len; h <<= 1)
     48     {
     49         Complex wn( cos(-on * 2 * PI / h), sin(-on * 2 * PI / h) );
     50         for(int j = 0; j < len; j += h)
     51         {
     52             Complex w(1, 0);
     53             for(int k = j; k < j + h/2; k++)
     54             {
     55                 Complex u = y[k];
     56                 Complex t = w * y[k + h/2];
     57                 y[k] = u + t;
     58                 y[k + h/2] = u - t;
     59                 w = w * wn;
     60             }
     61         }
     62     }
     63     if(on == -1)
     64         for(int i = 0; i < len; i++)
     65             y[i].x /= len;
     66 }
     67 //以上模板
     68 Complex x[MAXM];
     69 int a[MAXN];
     70 LL num[MAXM], sum[MAXN];
     71 int n, t;
     72 LL ans;
     73 int main()
     74 {
     75     scanf("%d", &t);
     76     while (t--)
     77     {
     78         int m,len;
     79         scanf("%d", &n);
     80         memset(num,0,sizeof(num));
     81         for (int i = 0; i < n; i++)
     82         {
     83             scanf("%d", &a[i]);
     84             num[a[i]]++;
     85         }
     86         sort(a,a+n);
     87         m = a[n-1] + 1;
     88         len = 1;
     89         while(len < 2 * m) len <<= 1;
     90         for(int i = 0; i < m; i++) x[i] = Complex(num[i], 0);
     91         for(int i = m; i < len; i++) x[i] = Complex(0, 0);
     92         FFT(x, len, 1);
     93         for(int i = 0; i < len; i++) x[i] = x[i] * x[i];
     94         FFT(x, len, -1);
     95         len = 2 *a[n-1];
     96         for(int i = 0; i <= len; i++) 
     97             sum[i] = (LL) (x[i].x + 0.5);
     98         for(int i = 0; i < n; i++)//减去两个取一样的 
     99             sum[a[i] + a[i]]--;
    100         for(int i = 0; i <= len; i++)//去掉重复 
    101             sum[i] /= 2; 
    102         for(int i = 1; i <= len; i++)
    103             sum[i] += sum[i-1];
    104         ans = 0;
    105         for(int i = 0; i < n; i++)//枚举最长边 
    106         {
    107             LL cnt = sum[len] - sum[a[i]];//两边之和大于最长边 
    108             cnt -= (LL) (n - i - 1) * i;//一边大,一边小 
    109             cnt -= (LL) (n - i - 1) * (n - i - 2) / 2;//两边都大于最长边 
    110             cnt -= (n - 1);//选了自己 
    111             ans += cnt;
    112         }
    113         LL tot = (LL) n * (n - 1) * (n - 2) / 6;
    114         printf("%.7f
    ",(double)ans/tot); 
    115     }
    116 }
    我自倾杯,君且随意
  • 相关阅读:
    Hibernate 查询,返回结果设置到DTO
    sqlserver计算时间差DATEDIFF 函数
    SQL语句 不足位数补0
    Redis详细用法
    windows下安装Redis并部署成服务
    Redis命令
    ajax请求在参数中添加时间戳
    JS获取子节点、父节点和兄弟节点的方法实例总结
    js关闭当前页面清除session
    Java面试题一览
  • 原文地址:https://www.cnblogs.com/nicetomeetu/p/5750751.html
Copyright © 2020-2023  润新知