【BZOJ3513-MUTC2013】idiots[生成函数+容斥]
作者:互联网
题意:
给一些长度的木棍,问你构成三角形的方案数。\(n<=10^5\)
思路:
计数问题。三角形构成条件中:两短边和大于第三边即可。
可以用生成函数(fft乘法)统计出所有由两条(不同)边构成的长度和及其方案数。
然后乘上比该和小的总个数。
会发现,对于三条边(三元组),如果构成三角形会被算\(3\)次,否则被算\(2\)次。
因此不构成三元组的数量为\(\binom{n}{3}*3-前面累计的总方案\)。
code
点击查看代码
#include<bits/stdc++.h>
using namespace std;
typedef double db;
typedef long long ll;
const int N=1e6+5;
const db pi=acos(-1);
struct cop {
db img,rl;
friend inline cop operator*(cop u,cop v) {return (cop){u.rl*v.img+u.img*v.rl,u.rl*v.rl-u.img*v.img};}
friend inline cop operator+(cop u,cop v) {return (cop){u.img+v.img,u.rl+v.rl};}
friend inline cop operator-(cop u,cop v) {return (cop){u.img-v.img,u.rl-v.rl};}
}f[N];
int rev[N],up,tot[N];
void gt_up(int len) {
up=1;int L=0;
while(up<=len){up<<=1;L++;}
for(int i=1;i<up;i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<(L-1));
}
void FFT(cop *a,int op) {
for(int i=1;i<up;i++)if(rev[i]>i)swap(a[i],a[rev[i]]);
for(int mid=1;mid<up;mid<<=1) {
cop w1=(cop){op*sin(pi/mid),cos(pi/mid)};
for(int len=mid<<1,l=0;l<up;l+=len) {
cop w=(cop){0,1};
for(int i=0;i<mid;i++,w=w*w1) {
int p=l+i,q=p+mid;
cop x=a[p],y=a[q]*w;
a[p]=x+y;a[q]=x-y;
}
}
}
}
int a[N],mxa;
int main() {
int T;scanf("%d",&T);
while(T--) {
mxa=0;
int n;scanf("%d",&n);
for(int i=0;i<n;i++) {int w;scanf("%d",&a[i]);tot[a[i]]++;mxa=max(mxa,a[i]);}
int mxa_=mxa<<1;
gt_up(mxa_);
for(int i=0;i<up;i++) {f[i]=(cop){0,tot[i]};}
FFT(f,-1);
for(int i=0;i<up;i++) {f[i]=f[i]*f[i];}
FFT(f,1);
ll res=0,sm=tot[1];
for(int i=2;i<=mxa_;i++) {
ll cnt=(ll)(f[i].rl/up+0.5);
if(!(i&1)) {cnt-=tot[i>>1];}
cnt>>=1;
res+=cnt*(sm-2);sm+=tot[i];
}
ll Cn_3=1ll*n*(n-1)*(n-2)/6;
res=Cn_3*3-res;
printf("%.7lf\n",(db)(Cn_3-res)/Cn_3);
for(int i=1;i<=mxa;i++)tot[i]=0;
}
return 0;
}
标签:cop,BZOJ3513,img,int,db,容斥,idiots,res,rl 来源: https://www.cnblogs.com/bestime/p/16442934.html