首页 > 其他 > 详细

BZOJ 3513 idiots

时间:2019-12-19 00:29:44      阅读:103      评论:0      收藏:0      [点我收藏+]

题目传送门

分析:

FFT一手统计两根棍子相加的方案

然后一个值2S可能会被同一根S自己乘自己得到

然后要减去

其次,A+B和B+A会被算成两种方案,所以还要除以2

然后不太好算合法的方案数,但是非法的很好算

直接减去小于S的所有方案数乘以长度为S的棍子数就好了。。

疯狂卡常2333

技术分享图片
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
 
#define maxn 500005
 
using namespace std;
 
inline int getint()
{
    int num=0,flag=1;char c;
    while((c=getchar())<0||c>9)if(c==-)flag=-1;
    while(c>=0&&c<=9)num=num*10+c-48,c=getchar();
    return num*flag;
}
 
struct cp{
    double a,b;
    cp(){}
    cp(double x,double y){a=x,b=y;}
    friend cp operator +(cp x,cp y)
    {return cp(x.a+y.a,x.b+y.b);}
    friend cp operator -(cp x,cp y)
    {return cp(x.a-y.a,x.b-y.b);}
    friend cp operator *(cp x,cp y)
    {return cp(x.a*y.a-x.b*y.b,x.a*y.b+x.b*y.a);}
};
 
const double pi=acos(-1.0);
int k=1,bit;
cp a[maxn],b[maxn];
int rev[maxn];
long long num1[maxn],num2[maxn];
 
inline void fft(cp *a,int inv)
{
    for(int i=0;i<k;i++)if(i<rev[i])swap(a[i],a[rev[i]]);
    for(int mid=1;mid<k;mid<<=1)
    {
        cp tmp(cos(pi/mid),inv*sin(pi/mid));
        for(int i=0;i<k;i+=mid*2)
        {
            cp ret(1,0);
            for(int j=0;j<mid;j++,ret=ret*tmp)
            {
                cp x=a[i+j],y=ret*a[i+j+mid];
                a[i+j]=x+y,a[i+j+mid]=x-y;
            }
        }
    }
}
 
int main()
{
    int T=getint();
    while(T--)
    {
        memset(a,0,sizeof a);
        int mx=0;
        long long n=getint();k=1,bit=0;
        for(int i=0;i<n;i++)
        {
            int x=getint();mx=max(mx,x);
            a[x].a++;
        }
        while(k<(mx+1)*2-1)k<<=1;
        while((1<<bit)<k)bit++;
        for(int i=0;i<k;i++)rev[i]=(rev[i>>1]>>1)|((i&1)<<(bit-1));
        for(int i=0;i<k;i++)b[i]=a[i];
        fft(a,1);
        for(int i=0;i<k;i++)a[i]=a[i]*a[i];
        fft(a,-1);
        for(int i=0;i<k;i++)
        {
            num1[i]=(long long)(b[i].a+0.5),
            num2[i]=(long long)(a[i].a/k+0.5);
            if(!(i&1))num2[i]-=num1[i>>1];
            num2[i]>>=1;
        }
        long long ans=(1ll*n*(n-1)*(n-2))/6;
        for(int i=1;i<=mx;i++)num2[i]+=num2[i-1],ans-=num2[i]*num1[i];
        printf("%.7lf\n",1.0*ans*6/(n*(n-1)*(n-2)));
    }
}
View Code

技术分享图片

BZOJ 3513 idiots

原文:https://www.cnblogs.com/Darknesses/p/12064468.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!