解题:HDU 4609 Three Idiots
Posted ydnhaha
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了解题:HDU 4609 Three Idiots相关的知识,希望对你有一定的参考价值。
要求组合的方法显然我们需要对桶卷积,即设$F(x)=sumlimits_{i=1}^{maxx}x^{cnt[i]}$,然后我们初步的先把$F^2(x)$卷出来,表示选两条边。然后我们发现如果用“两边之和大于第三边”来求,那么小于这两条边的可能不是最长的,所以应该枚举大于这两条边的来容斥
注意题目中提到了不能选重复的,所以对于所有指数为偶数的项去重,还有题目要求是无序地选
1 #include<cmath> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 const int N=400005,M=30,K=4e5; 7 const double pai=acos(-1); 8 struct cpx 9 { 10 double x,y; 11 }a[N]; 12 cpx operator + (cpx a,cpx b) 13 { 14 return (cpx){a.x+b.x,a.y+b.y}; 15 } 16 cpx operator - (cpx a,cpx b) 17 { 18 return (cpx){a.x-b.x,a.y-b.y}; 19 } 20 cpx operator * (cpx a,cpx b) 21 { 22 double x1=a.x,x2=b.x,y1=a.y,y2=b.y; 23 return (cpx){x1*x2-y1*y2,x1*y2+x2*y1}; 24 } 25 long long cnt[N],tot,ans; 26 int mem[N],rev[N],lgg[N]; 27 double Sin[M],Cos[M]; 28 int n,m,T,rd; 29 int Round(double x) 30 { 31 return (int)(x+0.5); 32 } 33 void Prework() 34 { 35 scanf("%d",&T); 36 for(int i=2;i<=K;i++) 37 lgg[i]=lgg[i>>1]+1; 38 for(int i=1;i<=25;i++) 39 Sin[i]=sin(2*pai/(1<<i)),Cos[i]=cos(2*pai/(1<<i)); 40 } 41 void Trans(cpx *c,int t) 42 { 43 for(int i=0;i<n;i++) 44 if(rev[i]>i) swap(c[rev[i]],c[i]); 45 for(int i=2;i<=n;i<<=1) 46 { 47 int len=i>>1; 48 cpx omg=(cpx){Cos[lgg[i]],Sin[lgg[i]]*t}; 49 for(int j=0;j<n;j+=i) 50 { 51 cpx ori=(cpx){1,0},tmp; 52 for(int k=j;k<j+len;k++,ori=ori*omg) 53 tmp=ori*c[k+len],c[k+len]=c[k]-tmp,c[k]=c[k]+tmp; 54 } 55 } 56 if(t==-1) for(int i=0;i<n;i++) c[i].x/=n; 57 } 58 int main() 59 { 60 Prework(); 61 while(T--) 62 { 63 scanf("%d",&n); 64 memset(mem,0,sizeof mem),m=0; 65 for(int i=1;i<=n;i++) 66 { 67 scanf("%d",&rd); 68 mem[rd]++,m=max(m,rd); 69 } 70 ans=tot=1ll*n*(n-1)*(n-2)/6,n=1; while(n<=m*2) n<<=1; 71 for(int i=0;i<n;i++) a[i].x=mem[i],a[i].y=0; 72 for(int i=0;i<n;i++) rev[i]=(rev[i>>1]>>1)+(i&1)*(n>>1); 73 Trans(a,1); 74 for(int i=0;i<n;i++) a[i]=a[i]*a[i]; 75 Trans(a,-1); 76 for(int i=1;i<=m;i++) cnt[i]=Round(a[i].x); 77 for(int i=1;i<=m;i++) 78 { 79 if(i%2==0) cnt[i]-=mem[i>>1]; 80 cnt[i]>>=1,cnt[i]+=cnt[i-1]; 81 } 82 for(int i=1;i<=m;i++) ans-=cnt[i]*mem[i]; 83 printf("%.7f ",(double)ans/tot); 84 } 85 return 0; 86 }
以上是关于解题:HDU 4609 Three Idiots的主要内容,如果未能解决你的问题,请参考以下文章