【FFT】HDU 4609 3-idiots

通道:http://acm.hdu.edu.cn/showproblem.php?pid=4609

题意:n条边长,求任选3条能组成三角形的概率。

思路:求出res后,减去一大一下,减去都大于它的边,减去该边和其他边组成的方案。

代码:

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <cmath>
  4 #include <algorithm>
  5
  6 const int N =400007;
  7
  8 typedef long long ll;
  9
 10 struct comp {
 11     double x, y;
 12     comp(double _x=0, double _y=0) : x(_x), y(_y) {}
 13 };
 14
 15 namespace FFT {
 16     const double pi2 = acos(-1.) * 2;
 17     comp a[N], b[N], tmp[N];
 18     int n, bn;
 19     ll res[N];
 20     inline comp W(int n, bool inv) {
 21         double ang = inv ? -pi2 / n : pi2 / n;
 22         return comp(cos(ang), sin(ang));
 23     }
 24     int bitrev(int x) {
 25         int ans = 0;
 26         for (int i=1; i<=bn; ++i)
 27             ans <<= 1, ans |= x & 1, x >>= 1;
 28         return ans;
 29     }
 30     void dft(comp *a,bool inv) {
 31         int step, to; comp w, wi, A, B;
 32         for (int i=0; i<n; ++i) {
 33             to = bitrev(i);
 34             if (to > i) std::swap(a[to], a[i]);
 35         }
 36         for (int i=1; i<=bn; ++i) {
 37             wi = W(1<<i, inv); w = comp(1, 0);
 38             step = 1 << (i-1);
 39             for (int k=0; k<step; ++k) {
 40                 for (int j=0; j<n; j+=1<<i) {
 41                     int t = j | k, d = j|k|step;
 42                     A = a[t];
 43                     B.x  = w.x * a[d].x - w.y * a[d].y;
 44                     B.y  = w.x * a[d].y + w.y * a[d].x;
 45                     a[t].x = A.x + B.x, a[t].y = A.y + B.y;
 46                     a[d].x = A.x - B.x, a[d].y = A.y - B.y;
 47                 }
 48                 comp tmp;
 49                 tmp.x = w.x * wi.x - w.y * wi.y;
 50                 tmp.y = w.x * wi.y + w.y * wi.x;
 51                 w = tmp;
 52             }
 53         }
 54     }
 55     int mul(int n1, int *x1, int n2, int *x2) {
 56         n = std::max(n1, n2);
 57         for (bn = 0; (1<<bn) < n; ++bn); ++bn;
 58         n = 1 << bn;
 59         for (int i=0; i<n; ++i) a[i] = b[i] = comp(0, 0);
 60         for (int i=0; i<n1; ++i) a[i] = comp(x1[i], 0);
 61         for (int i=0; i<n2; ++i) b[i] = comp(x2[i], 0);
 62         dft(a, false); dft(b, false);
 63         for (int i=0; i<n; ++i) {
 64             tmp[i].x = a[i].x * b[i].x - a[i].y * b[i].y;
 65             tmp[i].y = a[i].x * b[i].y + a[i].y * b[i].x;
 66         }
 67         dft(tmp, true);
 68         for (int i=0; i<n; ++i) res[i] = (ll)(tmp[i].x/n + 0.1);
 69         for (--n; n && !res[n]; --n);
 70         return n+1;
 71     }
 72 };
 73
 74 int n;
 75 int a[N], num[N];
 76 ll sum[N];
 77
 78 int main() {
 79     int T;
 80     scanf("%d", &T);
 81     while (T-- > 0) {
 82         scanf("%d", &n);
 83         int up = 0;
 84         for (int i = 0; i < n; ++i) scanf("%d", &a[i]), up = std::max(up, a[i]);
 85         memset(num, 0, sizeof num);
 86         for (int i = 0; i < n; ++i) ++num[a[i]];
 87         int len = FFT::mul(up + 1, num, up + 1, num);
 88         for (int i = 0; i < n; ++i) {
 89             --FFT::res[a[i] + a[i]];
 90         }
 91         for (int i = 0; i < len; ++i) {
 92             FFT::res[i] >>= 1;
 93         }
 94         sum[0] = FFT::res[0];
 95         for (int i = 1; i < len; ++i) {
 96             sum[i] = sum[i - 1] + FFT::res[i];
 97         }
 98         ll ans = 0;
 99         for (int i = 0; i < n; ++i) {
100             ans += sum[len - 1] - sum[a[i]];
101             ans -= n - 1, ans -= (ll) i * (n - 1 - i);
102             ans -= (ll) (n - 1 - i) * (n - 2 - i) / 2;
103         }
104         ll tot = (ll) n * (n - 1) * (n - 2) / 6;
105         printf("%.7f\n", 1. * ans / tot);
106     }
107     return 0;
108 }

时间: 2024-10-12 19:45:01

【FFT】HDU 4609 3-idiots的相关文章

【FFT】HDU 5307 He is Flying

通道:http://acm.hdu.edu.cn/showproblem.php?pid=5307 题意:给出n个数,然后求所有的dp[i],这里的dp[i]就是所有连续区间内和为i的区间长度总和 代码: 感谢沈洋. 1 #include <cstdio> 2 3 typedef long long ll; 4 5 const int N = 262145, BUF_SIZE = N * 10, BF_LIM = 16; 6 7 namespace BF { 8 void mul(ll *a,

【multiset】hdu 5349 MZL&#39;s simple problem

[multiset]hdu 5349 MZL's simple problem 题目链接:hdu 5349 MZL's simple problem 题目大意 n次操作,插入元素.删除最小元素.查询最大元素并输出. C++STL的multiset的使用 set--多元集合(元素不可重复),multiset--可重复元素的多元集合 多元集合(MultiSets)和集合(Sets)相像,只不过支持重复对象.(具体用法请参照set容器) set和multiset内部是以平衡二叉树实现的: 从内部数据结

矩阵十题【三】 HDU 1588 Gauss Fibonacci

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1588 题目大意:先要知道一组斐波那契数列 i 0 1 2 3 4 5 6 7 f(i) 0 1 1 2 3 5 8 13 下面给你一组数: k,b,n,M 现在知道一组公式g(i)=k*i+b:(i=0,1,2,3...n-1) 让你求出 f(g(i)) 的总和(i=01,2,3,...,n-1),比如给出的数据是2 1 4 100 2*0+1=1   f(1)=1 2*1+1=3   f(3)=2

【网络流】hdu 1569 方格取数(2)

/* 和1565一样: 总点数的权 - 最小覆盖点集 = 最大独立集 -------------------------------------- void add(int u, int v, int f)加边 { e[ct].u = u; e[ct].v = v; e[ct].f = f; next[ct] = first[u]; first[u] = ct++; e[ct].u = v; e[ct].v = u; e[ct].f = 0; next[ct] = first[v]; first

【FFT】专题总结

学了若干天终于学(bei)会了传说中的法法塔 感觉也没那么难用嘛 fft快速傅里叶变换 在大表课件上写就是解决高精乘的工具 其实很有理有据 fft就是用复数的折半引理优化两个多项式相乘的高端东西 他能使O(n^2)的多项式相乘优化到O(nlogn) 听ak说这也是比较模板的东西 也就不去理解什么证明了(其实是我看了半天看不懂TAT) 贴个代码吧(史上最短总结233- -) 1 int bit_rev(int t,int n){ 2 int res=0; 3 for (int i=0;i<n;i+

【floyd】HDU 1874 畅通工程续

之后的题解偏重实用/总结性质,尽量理解算法本身而不是题,时间复杂度什么的也可以放放. 很久之前做过这个题,当时使用dijkstra做的,关于几个最短路算法,分类的话可以分为以下几种. 1.单源最短路:已知起点(终点),计算从源点到其他各个顶点的最短路径长度. 典型算法:Dijkstra,Bellman-Ford(可以算负的,比较慢),spfa(负权能用,加了松弛操作,速度比较炸天) 2.全局最短路:从一点到另一点,典型如Floyd,A*启发式算法. 重新用floyd写一遍: #include <

【bfs】hdu 1104 Remainder

[bfs]hdu 1104 Remainder 题目链接:hdu 1104 Remainder 很不错的一道搜索题目,但是有几个关键问题要注意. 最短路径,果断bfs+Queue 路径的存储问题,之前只想把每一步的计算结果存储到queue(int)Q中,后来发现路径无法记录,就选择存储节点的方式并用string保存路径,queue(node)Q,开一个临时的节点node p,每进行一次运算就更新它的路径string+'op',最终输出的一定是完整路径!! 但最关键的是取模!!!!! discus

【dfs】hdu 1016 Prime Ring Problem

[dfs]hdu 1016 Prime Ring Problem 题目链接 刚开始接触搜索,先来一道基本题目练练手. 注意对树的深度进行dfs dfs过程中注意回退!!! 素数提前打表判断快一些 参考代码 /*Author:Hacker_vision*/ #include<bits/stdc++.h> #define clr(k,v) memset(k,v,sizeof(k)) using namespace std; const int _max=1e3+10;//素数打表 int n,pr

【搜索】HDU 5348 MZL&#39;s endless loop

通道 题意:给出n个点,m条边,现在要给边定向使得点的出度和入度的差不超过1 思路: 对每个点进行出度和入度的判断,如果出度大,就先进行反向的搜索(每搜索一条边u,v就认为这是一条v到u的有向边),反之,进行正向搜索(每搜到一条边u,v认为这是一条u到v的有向边),一直搜索到找不到边能继续为止,每条边只遍历一次 代码: #pragma comment(linker, "/STACK:102400000,102400000") #include <cstdio> #inclu