原题题面
King OMeGa catched three men who had been streaking in the street. Looking as idiots though, the three men insisted that it was a kind of performance art, and begged the king to free them. Out of hatred to the real idiots, the king wanted to check if they were lying. The three men were sent to the king’s forest, and each of them was asked to pick a branch one after another. If the three branches they bring back can form a triangle, their math ability would save them. Otherwise, they would be sent into jail.
However, the three men were exactly idiots, and what they would do is only to pick the branches randomly. Certainly, they couldn’t pick the same branch - but the one with the same length as another is available. Given the lengths of all branches in the forest, determine the probability that they would be saved.
输入格式
An integer T(T≤100)T(T≤100)T(T≤100) will exist in the first line of input, indicating the number of test cases.
Each test case begins with the number of branches N(3≤N≤105)N(3≤N≤10^5)N(3≤N≤105).
The following line contains NNN integers ai(1≤ai≤105)a_i (1≤a_i≤10^5)ai(1≤ai≤105), which denotes the length of each branch, respectively.
输出格式
Output the probability that their branches can form a triangle, in accuracy of 7 decimal places.
输入样例
2
4
1 3 3 4
4
2 3 3 4
输出样例
0.5000000
1.0000000
题面分析
给定n个点,随机取3条边,求能组成三角形的概率。
答案很简单,就是∑i=1n∑j=1n∑k=1n[ai+aj>ak](i≠j≠k)Cn3\frac{\sum_{i=1}^{n}{\sum_{j=1}^{n}{\sum_{k=1}^{n}[a_i+a_j>a_k](i\neq j\neq k)}}}{C_{n}^{3}}Cn3∑i=1n∑j=1n∑k=1n[ai+aj>ak](i=j=k)
首先我们要计算出任意两条边两两相加的结果,即∑i=1n∑j=1n(ai+aj)(i≠j)\sum_{i=1}^{n}{\sum_{j=1}^{n}{(a_i+a_j)(i\neq j)}}∑i=1n∑j=1n(ai+aj)(i=j)
只需要对aaa做卷积,然后减去i=ji=ji=j的情况后除以2(取两条边不分先后)。
于是我们只要统计所有的ai+aj<=aka_i+a_j<=a_kai+aj<=ak的个数再从1里减掉即可。
#include<bits/stdc++.h>
using namespace std;
const int maxn=4e5;
#define cp complex<double>
#define ll long long
cp a[maxn+10];
const double pi=acos(-1.0);
ll rev[maxn+10];
int getBit(int n)
{
int len=1;
while(len<(n<<1)) len<<=1;
for(int i=0; i<len; i++) rev[i]=(rev[i>>1]>>1)|(i&1 ? len>>1 : 0);
return len;
}
void FFT(cp *a, int n, int flag)
//inv是1时是系数转点值,-1是点值转系数
{
for(int i=0; i<n; ++i)
{
if (i<rev[i]) swap(a[i], a[rev[i]]);
}
for(int mid=1; mid<n; mid*=2)
{
cp w(cos(pi*1.0/mid), flag*sin(pi*1.0/mid));//单位根
for(int i=0; i<n; i+=mid*2)
{
cp omega(1, 0);
for(int j=0; j<mid; j++, omega*=w)
{
cp x=a[i+j];
cp y=omega*a[i+j+mid];
a[i+j]=x+y;
a[i+j+mid]=x-y;
}
}
}
}
ll cnt[maxn+10];
ll b[maxn+10];
ll prefix[maxn+10];
ll num[maxn+10];
void solve()
{
int t;
scanf("%d", &t);
while(t--)
{
int n;
scanf("%d", &n);
memset(cnt, 0, sizeof(cnt));
for(int i=0; i<n; ++i)
{
scanf("%lld", &b[i]);
cnt[b[i]]++;
}
sort(b, b+n);
ll limit=getBit(b[n-1]+1);//数组是0~b[n-1]
for(int i=0; i<limit; ++i)
{
a[i].real(i<=b[n-1] ? cnt[i] : 0);
a[i].imag(0);
// printf("%.f ", a[i].real());
}
// printf("\n");
FFT(a, limit, 1);
for(int i=0; i<limit; ++i)
{
a[i]*=a[i];
}
FFT(a, limit, -1);
for(int i=0; i<limit; ++i)
{
num[i]=(ll)(a[i].real()/limit+0.5);
}
for(int i=0; i<n; ++i)
{
num[b[i]+b[i]]--;
//把自己的和自己的去掉
}
prefix[0]=0;
for(int i=1; i<=b[n-1]*2; ++i)//(0~2*b[n-1])
{
num[i]/=2;
prefix[i]=prefix[i-1]+num[i];//A取B和B取A是同一种,取前缀和
}
ll ans=0;
for(int i=0; i<n; ++i)
{
ans+=prefix[b[i]];//统计两条之和小于b[i]的
}
ll total=(ll) n*(n-1)*(n-2)/6;
// printf("%lld %lld\n", ans, total);
printf("%.7lf\n", 1.0-(double) ans/total);
}
}
signed main()
{
// ios_base::sync_with_stdio(false);
// cin.tie(0);
// cout.tie(0);
#ifdef ACM_LOCAL
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
long long test_index_for_debug=1;
char acm_local_for_debug;
while(cin>>acm_local_for_debug)
{
cin.putback(acm_local_for_debug);
if (test_index_for_debug>100)
{
throw runtime_error("Check the stdin!!!");
}
auto start_clock_for_debug=clock();
solve();
auto end_clock_for_debug=clock();
cout<<"\nTest "<<test_index_for_debug<<" successful"<<endl;
cerr<<"Test "<<test_index_for_debug++<<" Run Time: "
<<double(end_clock_for_debug-start_clock_for_debug)/CLOCKS_PER_SEC<<"s"<<endl;
cout<<"--------------------------------------------------"<<endl;
}
#else
solve();
#endif
return 0;
}
后记
感谢HDU-ILLLZKQF提供的思路协助。施聚nb!
DrGilbert 2020.10.8