HDU 4609 3-idiots

FFT计算卷积

#include<bits/stdc++.h>
using namespace std;

const int MAXN=1<<18;
const long long mod=998244353;
const int G=3;
long long rev[MAXN],w[2][MAXN];
long long fac[MAXN],inv[MAXN];
long long A[MAXN];

long long powmod(long long x,long long p)
{
	long long ret=1;
	while(p)
	{
		if(p&1)
			ret=ret*x%mod;
		x=x*x%mod;
		p>>=1;
	}
	return ret;
}

void init()
{
	fac[0]=1;
	for(int i=1;i<MAXN;i++)
		fac[i]=fac[i-1]*i%mod;
	inv[MAXN-1]=powmod(fac[MAXN-1],mod-2);
	for(int i=MAXN-2;i>=0;i--)
		inv[i]=inv[i+1]*(i+1)%mod;
}

void initfft(int n)
{
	int i,k,x,y,v,dv;
	for(i=0;i<=n-1;i++)
	{
		x=i;
		y=0;
		for(k=1;k<n;k<<=1,x>>=1)
			(y<<=1)|=(x&1);
		rev[i]=y;
	}
	v=powmod(G,(mod-1)/n);
	dv=powmod(v,mod-2);
	w[0][0]=w[1][0]=1;
	for(i=1;i<=n-1;i++)
	{
		w[0][i]=w[0][i-1]*v%mod;
		w[1][i]=w[1][i-1]*dv%mod;
	}
}

inline void fft(long long *A,int n,int ff)
{
	int i,j,k,t,l,v,x,y;
	for(i=0;i<=n-1;i++)
	{
		if(i<rev[i])
			swap(A[i],A[rev[i]]);
	}
	for(i=1;i<n;i<<=1)
	{
		for(j=0,t=n/(i<<1);j<n;j+=(i<<1))
		{
			for(k=0,l=0;k<i;k++,l+=t)
			{
				x=A[i+j+k]*w[ff][l]%mod;
				y=A[j+k];
				A[j+k]=(x+y)%mod;
				A[i+j+k]=(y+mod-x)%mod;
			} 
		}
	}
	if(ff)
	{
		v=powmod(n,mod-2);
		for(i=0;i<=n-1;i++)
			A[i]=A[i]*v%mod;
	}
}

int num[MAXN];

int main()
{
	int T,n,i,m,mx,x;
	long long sum,tmp;
	double ans;
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d",&n);
		memset(num,0,sizeof(num));
		mx=0;
		for(i=0;i<n;i++)
		{
			scanf("%d",&x);
			num[x]++;
			mx=max(mx,x);
		}
		m=1;
		while(m<=2*mx+2)
			m<<=1;
		initfft(m);
		for(i=0;i<m;i++)
			A[i]=num[i];
		fft(A,m,0);
		for(i=0;i<m;i++)
			A[i]=A[i]*A[i]%mod;
		fft(A,m,1);
		for(i=0;i<m;i++)
		{
			if(!(i&1))
				A[i]-=num[i>>1];
			A[i]>>=1;
		}
		tmp=0;
		sum=0;
		for(i=1;i<m;i++)
		{
			tmp+=A[i];
			sum+=tmp*num[i];
			
		}
		ans=1.0-sum*6.0/n/(n-1)/(n-2);
		printf("%.7f\n",ans);
	} 
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值