ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

[BZOJ3513] idiots - FFT,组合数学

2020-10-08 10:03:10  阅读:177  来源: 互联网

标签:BZOJ3513 组合 int memset -- idiots FFT sizeof define


Description

给定 \(n\) 条边的长度,任选三条边(组合),求能组成三角形的概率。

Solution

首先预处理出任选两条边(可以重复且不限顺序)每种长度和 \(i\) 对应的方案数 \(c[i]\),这个很显然可以用 FFT 求出。

考虑如何修正为组合数,对于每条边 \(a_i\),将 \(c[2a_i]\) 减去 \(1\),即去除将这条边重复选两次的情况。尔后,对所有 \(c[i]\) 除以 \(2\),即去除顺序。这样得到的 \(c[i]\) 就是选择两条不同的边,边长和为 \(i\) 的组合数。

现考虑枚举最长边来计算答案,假设当前最长边为 \(a_i\),则对答案的贡献为

\[\sum_{j=a_i+1}^{\infty} c[i]-(i-1)(n-i)-\frac{(n-i)(n-i-1)}{2}-(n-1) \]

其中第二项为一大一小的方案数,第三项为两大的方案数,第四项为选重了该边的方案数。

#include<bits/stdc++.h>
#define N 262145
#define pi acos(-1)
using namespace std;

#define int long long 

namespace po {
typedef complex<double> E;
int n,m,L;
int R[N];
E a[N],b[N];

void fft(E *a,int f){
	for(int i=0;i<n;i++)if(i<R[i])swap(a[i],a[R[i]]);
	for(int i=1;i<n;i<<=1){
		E wn(cos(pi/i),f*sin(pi/i));
		for(int p=i<<1,j=0;j<n;j+=p){
			E w(1,0);
			for(int k=0;k<i;k++,w*=wn){
				E x=a[j+k],y=w*a[j+k+i];
				a[j+k]=x+y;a[j+k+i]=x-y;
			}
		}
	}
}

void mul(int _n,int *aa,int *bb,int *cc){
    n=_n;
    memset(a,0,sizeof a);
    memset(b,0,sizeof b);
    memset(R,0,sizeof R);
    L=0;
    m=n;
	for(int i=0,x;i<=n;i++)a[i]=aa[i];
	for(int i=0,x;i<=m;i++)b[i]=bb[i];
	m*=2;
	for(n=1;n<=m;n<<=1)L++;
	for(int i=0;i<n;i++)R[i]=(R[i>>1]>>1)|((i&1)<<(L-1));
	fft(a,1);fft(b,1);
	for(int i=0;i<=n;i++)a[i]=a[i]*b[i];
	fft(a,-1);
	memset(cc,0,sizeof cc);
	for(int i=0;i<=m;i++) cc[i]=(int)(a[i].real()/n+0.5);
}
}

using po::mul;

int n,a[N],b[N],c[N],d[N];

void solve()
{
    cin>>n;
    memset(a,0,sizeof a);
    memset(b,0,sizeof b);
    memset(c,0,sizeof c);
    for(int i=1;i<=n;i++) cin>>a[i];
    for(int i=1;i<=n;i++) b[a[i]]++;
    int m=*max_element(a+1,a+n+1);
    mul(m+1,b,b,c);
    m=(m+1)*2;
    for(int i=1;i<=n;i++) c[2*a[i]]--;
    for(int i=0;i<=m;i++) c[i]/=2;
    for(int i=m;i>=0;--i) c[i]+=c[i+1];
    int ans=0;
    for(int i=1;i<=n;i++)
    {
        ans+=c[a[i]+1];
        ans-=(i-1)*(n-i);
        ans-=(n-i)*(n-i-1)/2;
        ans-=n-1;
    }
    printf("%.7lf\n",1.0*ans/n/(n-1)/(n-2)*6);
}

signed main()
{
    ios::sync_with_stdio(false);

    int t;
    cin>>t;
    while(t--)
    {
        solve();
    }

    return 0;
}

/*
2 
4 
1 3 3 4 
4 
2 3 3 4
*/

标签:BZOJ3513,组合,int,memset,--,idiots,FFT,sizeof,define
来源: https://www.cnblogs.com/mollnn/p/13780399.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有