解题:HDU 4609 Three Idiots

题面

要求组合的方法显然我们需要对桶卷积,即设$F(x)=\sum\limits_{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\n",(double)ans/tot);
84     }
85     return 0;
86 }
View Code

猜你喜欢

转载自www.cnblogs.com/ydnhaha/p/10200331.html
今日推荐