HDU 4609 3-idiots(FFT)

题意:给出n个正整数(数组A)。每次随机选出三个数。问这三个数能组成三角形的概率为多大?

首先,我们用类似桶排计数的方法作出两个数组a,b,储存每个长度有几条边,然后对两个数组求卷积。

求出卷积后,这就代表了2条边能构成的边长度的集合了,注意,由于求卷积的时候可能把两条相同的边相加,所以最后求出的数组一定要减去这重复的部分,然后,先算x后算y等价于先算y后算x,所以要除以二。

然后,对于第三条边a[i],我们这样考虑:令它作为这三条边中最大的那条!

所以之前的卷积求出来的两边和一定会比这条边大,所以每次都计数:ans+=sum[mx]-sum[a[i]];

然后减去重复部分:

(1)一个选了i后面,一个选了i前面 (减去(i-1)*(n-i)个)

(2)一个选了i,另一个随意 (减去n-1个)

(3)两个都是i后面的 (减去C(n-i,2)个);

非常interesting的题目!

 1 #include<algorithm>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<cstring>
 5 #include<iostream>
 6 #include<complex>
 7 #define N 300005
 8 #define ll long long
 9 typedef std::complex<double> cd;
10 int a[400005];
11 ll C[400005],Sum[400005],A[400005],B[400005];
12 int n,mxnum;
13 int bitrev(int t,int n){
14     int res=0;
15     for (int i=0;i<n;i++) res|=((t>>(n-i-1))&1)<<i;//括号要多加
16     return res;
17 }
18 void fft(cd *a,int n,int rev){
19     int len=1<<n;
20     static cd y[N];double Pi=acos(-1);
21     for (int i=0;i<len;i++) y[i]=a[bitrev(i,n)];
22     for (int d=1;d<len;d<<=1){
23         cd wn(exp(cd(0,Pi*rev/d)));
24         for (int k=0;k<len;k+=2*d){
25             cd w(1,0);
26             for (int i=k;i<k+d;i++,w*=wn){
27                 cd u=y[i],v=w*y[i+d];
28                 y[i]=u+v;
29                 y[i+d]=u-v;
30             }
31         }
32     }
33     if (rev==-1)
34     for (int i=0;i<len;i++) y[i]/=len;
35     for (int i=0;i<len;i++) a[i]=y[i];
36 }
37 void mul(ll *a,int la,ll *b,int lb,ll *c,int &lc){
38     int len=1,n=0;
39     static cd t1[N],t2[N];
40     for (;len<la*2||len<lb*2;len<<=1,n++);
41     for (int i=0;i<la;i++) t1[i]=cd(a[i],0);
42     for (int i=0;i<lb;i++) t2[i]=cd(b[i],0);
43     for (int i=la;i<len;i++) t1[i]=cd(0,0);
44     for (int i=lb;i<len;i++) t2[i]=cd(0,0);
45     fft(t1,n,1);fft(t2,n,1);
46     for (int i=0;i<len;i++) t1[i]*=t2[i];
47     fft(t1,n,-1);
48     for (int i=0;i<len;i++) c[i]=(long long)(t1[i].real()+0.5);
49     lc=len;
50 }
51 int main(){
52     int T;
53     scanf("%d",&T);
54     while (T--){
55         scanf("%d",&n);
56         for (int i=1;i<=n;i++) scanf("%d",&a[i]);
57         mxnum=0;
58         for (int i=1;i<=n;i++) mxnum=std::max(mxnum,a[i]);
59         for (int i=1;i<=n;i++) A[a[i]]++,B[a[i]]++;
60         int lc;
61         mul(A,mxnum+1,B,mxnum+1,C,lc);
62         for (int i=1;i<=n;i++) C[a[i]*2]--;
63         for (int i=1;i<=mxnum*2;i++) C[i]/=2;
64         Sum[0]=0;
65         for (int i=1;i<=mxnum*2;i++)
66          Sum[i]=Sum[i-1]+C[i];
67         std::sort(a+1,a+1+n);
68         ll ans=0;
69         for (int i=1;i<=n;i++){
70             ans+=Sum[mxnum*2]-Sum[a[i]];
71             ans-=(ll)n-1;
72             ans-=(ll)(i-1)*(n-i);
73             ans-=(ll)(n-i)*(n-i-1)/2;
74         }
75         ll sum=(ll)(n)*(n-1)*(n-2)/6;
76         printf("%.7f\n",(double)1.0*((double)(ans))/((double)sum));
77         for (int i=0;i<=mxnum;i++) A[i]=B[i]=Sum[i]=C[i]=0;
78     }
79 }
时间: 2024-10-08 20:27:09

HDU 4609 3-idiots(FFT)的相关文章

HDU 5763 Another Meaning(FFT)

[题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=5763 [题目大意] 给出两个串S和T,可以将S串中出现的T替换为*,问S串有几种表达方式. [题解] 我们定义数组f为S串中T出现的最后一个字母所在的位置,那么ans[i]=ans[i-1]+f[i-1]?ans[i-lenT]:0,一遍递推即可,所以关键就在于求出f数组了,f数组可以用kmp求,由于最近练FFT,用FFT求距离卷积匹配为0的位置,就是f数组了. [代码] #include <c

Hdu 1402 (FFT)

题目链接 A * B Problem Plus Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 12490    Accepted Submission(s): 2206 Problem Description Calculate A * B. Input Each line will contain two integers A and

HDU 1045 - Fire Net (最大独立集)

题意:给你一个正方形棋盘.每个棋子可以直线攻击,除非隔着石头.现在要求所有棋子都不互相攻击,问最多可以放多少个棋子. 这个题可以用搜索来做.每个棋子考虑放与不放两种情况,然后再判断是否能互相攻击来剪枝.最后取可以放置的最大值. 这里我转化成求最大独立集来做. 首先将每个空地编号,对于每个空地,与该位置可以攻击到的空地连边.找最多的空地使得不互相攻击,即求该图的最大独立集.与搜索做法基本一致,但是说法略有不同. 1 #include<iostream> 2 #include<cstring

hdu oj1102 Constructing Roads(最小生成树)

Constructing Roads Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 13995    Accepted Submission(s): 5324 Problem Description There are N villages, which are numbered from 1 to N, and you should

HDU 1863 畅通工程 (最小生成树)

Problem Description 省政府"畅通工程"的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可).经过调查评估,得到的统计表中列出了有可能建设公路的若干条道路的成本.现请你编写程序,计算出全省畅通需要的最低成本. Input 测试输入包含若干测试用例.每个测试用例的第1行给出评估的道路条数 N.村庄数目M ( < 100 ):随后的 N 行对应村庄间道路的成本,每行给出一对正整数,分别是两个村庄的编号,以及此两村庄间

hdu 3650 Hot Expo(贪心)

转载请注明出处:http://blog.csdn.net/u012860063?viewmode=contents 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3650 --------------------------------------------------------------------------------------------------------------------------------------------

hdu 4970 Killing Monsters(数学题)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4970 Problem Description Kingdom Rush is a popular TD game, in which you should build some towers to protect your kingdom from monsters. And now another wave of monsters is coming and you need again to k

HDU 3572 Task Schedule(ISAP)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3572 题意:m台机器,需要做n个任务.第i个任务,你需要使用机器Pi天,且这个任务要在[Si  ,  Ei]区间内完成才有效.对于一个任务,只能由一个机器来完成,一个机器同一时间只能做一个任务.当然,一个任务可以分成几段不连续的时间来完成.问,能否做完全部任务. 题意很清晰,也就是判断是否是满流. 对于网络流问题,模板大家都有,关键在于如何建图(详见资料) 思路:今天问了龙哥,对建图有了一定的了解,

hdu 1728 逃离迷宫 (BFS)

逃离迷宫 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 14376    Accepted Submission(s): 3458 Problem Description 给定一个m × n (m行, n列)的迷宫,迷宫中有两个位置,gloria想从迷宫的一个位置走到另外一个位置,当然迷宫中有些地方是空地,gloria可以穿越,有些地方

HDU 4563 御剑术I(背包)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4563 题意:一个点开始在原点.有n个命令.第i个命令施加到这个点时,这个点的速度为(Vxi,Vyi),即在x方向的速度为Vxi,在y方向的速度为 Vyi.并且这个命令施加到点时之前的速度全部消失.每种命令最多使用一次.问在x方向走长度为m时在y方向的最大高度是多少?每种命令只能在整数时刻施 加. 思路:首先,每种命令使用的先后顺序显然是没有关系的.除了最后一个施加的命令,之前的命令必然都是使用了整数