zoukankan      html  css  js  c++  java
  • bzoj3771: Triple

    码完这题有一种很爽很放松的感觉。。。155行。。。2.5个中午+1个早上真的值,毕竟我没mod题解啊!!!

    这题一开始想的时候就想到了补0价值的斧头,然后FFT三次,结果发现有什么重复取一个啊,取的顺序啊牵扯出容斥啊,组合数什么的非常尴尬,然后一个半中午就玩没了,然后决定分开做,因为0太难搞了,可以视成很多种情况。

    然后我就发现取一个和两个我很容易就可以搞,就是补0价值的斧头之后,FFT一次,然后可以发现,就有取a斧头和b斧头的顺序问题,那就除一下2

    那么问题就转化为取三个斧头的情况了。

    那就先自乘三次,就得到了斧头无限,顺序不同也算不同方案的方案数

    首先先解决取了相同斧头的问题,那么ans在这个意义上是第1,2,3取的都不一样的方案 - 3*第1,2,3取的有两个一样的方案 + 2*第1,2,3取的有三个一样的方案(可能有人不理解这个方案为什么要*2,是因为比如取的是6,6,6,那它减了三次,实际上只需要减两次就好了。)

    然后三个都一样的可以预处理吧,两个一样的就再跑一个FFT,怎么跑?想象一下,我们把两个相同的斧头捆在一起,然后让它和柿子再乘一次,就可以得到两个一样的情况。

    接着就是顺序的问题了,三个都一样的没有这个问题不管ta,

    有个栗子(打表推的):

    比如4 5 6 8 ,得到18有10种

    10:(5,5),(4,6),(6,4) 再+8

    12:(6,6),(4,8),(8,4) 再+6

    13:(5,8),(8,5) 再+5

    14:(6,8),(8,6) 再+4

    两个一样的情况就是(5,5,8)和(6,6,6)

    分析一下,两个一样的情况有三种不同的组合,那就减掉

    剩下就是都不一样的了,很容易发现有6种组合,那除一下,再把一样的加上

    最后答案就是1/2的方案加3的方案了~

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    const double pi=acos(-1.0);
    
    struct Complex
    {
        double r,i;
        Complex(){r=0, i=0;}
        Complex(double _r,double _i){r=_r, i=_i;}
        friend Complex operator +(Complex x,Complex y){return Complex(x.r+y.r,x.i+y.i);}
        friend Complex operator -(Complex x,Complex y){return Complex(x.r-y.r,x.i-y.i);}
        friend Complex operator *(Complex x,Complex y){return Complex(x.r*y.r-x.i*y.i,x.r*y.i+x.i*y.r);}
    }T[410000],A[410000],B[410000];
    int d[410000],d2[410000],len;
    
    int R[410000];
    void fft(Complex *a,int n,int op)
    {
        for(int i=0;i<n;i++)
            if(i<R[i])swap(a[i],a[R[i]]);
            
        for(int i=1;i<n;i*=2)
        {
            Complex wn(cos(pi/i),sin(pi*op/i));
            for(int j=0;j<n;j+=(i<<1))
            {
                Complex w(1,0);
                for(int k=0;k<i;k++,w=w*wn)
                {
                    Complex a1=a[j+k],a2=a[j+k+i];
                    a[j+k]  =a1+w*a2;
                    a[j+k+i]=a1-w*a2;
                }
            }
        }
    }
    
    void FFT1(int n,int m)
    {
        int nn=n,L=0;
        for(int i=0;i<=n;i++)A[i].r=B[i].r=T[i].r;
        m=m+n;for(n=1;n<=m;n*=2)L++;
        for(int i=0;i<n;i++)R[i]=(R[i>>1]>>1)|((i&1)<<(L-1));
        
        fft(A,n,1);fft(B,n,1);
        for(int i=0;i<n;i++)A[i]=A[i]*B[i], B[i].r=0, B[i].i=0;
        
        fft(A,n,-1);
        for(int i=0;i<n;i++)
            A[i].r=int(A[i].r/n+0.5), A[i].i=0;
        
        for(int i=1;i<n;i++)A[i].r/=2;
        
        for(int i=0;i<n;i++)d[i]+=int(A[i].r), A[i].r=0, A[i].i=0;
        len=m;
        //第一次FFT,解决用1/2个不同物品组成不同价值
    }
    void FFT2(int n,int m)
    {
        int nn=n,L=0;
        for(int i=0;i<=n;i++)A[i].r=B[i].r=T[i].r;
        m=m+n;for(n=1;n<=m;n*=2)L++;
        for(int i=0;i<n;i++)R[i]=(R[i>>1]>>1)|((i&1)<<(L-1));
        
        fft(A,n,1);fft(B,n,1);
        for(int i=0;i<n;i++)A[i]=A[i]*B[i], B[i].r=0, B[i].i=0;
        
        fft(A,n,-1);
        for(int i=0;i<n;i++)
        {
            A[i].r=int(A[i].r/n+0.5), A[i].i=0;
    //        if(int(A[i].r)!=0)printf("%d %d
    ",i,int(A[i].r));
        }
    //    printf("
    ");
    
    
        n=nn;L=0;
        for(int i=0;i<=n;i++)B[i].r=T[i].r;
        m=m+n;for(n=1;n<=m;n*=2)L++;
        for(int i=0;i<n;i++)R[i]=(R[i>>1]>>1)|((i&1)<<(L-1));
        
        fft(A,n,1);fft(B,n,1);
        for(int i=0;i<n;i++)A[i]=A[i]*B[i], B[i].r=0, B[i].i=0;
        
        fft(A,n,-1);
        for(int i=0;i<n;i++)
        {
            A[i].r=int(A[i].r/n+0.5), A[i].i=0;
    //        if(int(A[i].r)!=0)printf("%d %d
    ",i,int(A[i].r));
        }
    //    printf("
    ");
        
        for(int i=0;i<n;i++)d2[i]+=int(A[i].r), A[i].r=0, A[i].i=0;
        len=m;
        
    //    for(int i=0;i<=len;i++)
        //    if(d[i]!=0)printf("%d %d
    ",i,d[i]);
    }
    void FFT3(int n,int m)
    {
        int nn=n,L=0;
        for(int i=0;i<=n;i++)A[i+i].r=B[i].r=T[i].r;
        
        m=m+n;for(n=1;n<=m;n*=2)L++;
        for(int i=0;i<n;i++)R[i]=(R[i>>1]>>1)|((i&1)<<(L-1));
        
    /*    for(int i=0;i<n;i++)
            if(int(A[i].r)!=0)printf("%d %d
    ",i,int(A[i].r));
        for(int i=0;i<n;i++)
            if(int(B[i].r)!=0)printf("%d %d
    ",i,int(B[i].r));
    */        
        fft(A,n,1);fft(B,n,1);
        for(int i=0;i<n;i++)A[i]=A[i]*B[i], B[i].r=0, B[i].i=0;
        
        fft(A,n,-1);
        for(int i=0;i<n;i++)
            A[i].r=int(A[i].r/n+0.5), A[i].i=0;
            
    //    for(int i=0;i<n;i++)
    //        if(int(A[i].r)!=0)printf("%d %d
    ",i,int(A[i].r));
            
        for(int i=0;i<n;i++)d2[i]-=int(A[i].r)*3, A[i].r=0, A[i].i=0;
        
        for(int i=1;i<=len;i++)
        {
            d2[i]/=6;d2[i]+=d[i];
            if(d2[i]!=0)
                printf("%d %d
    ",i,d2[i]);
        }
    }
    int main()
    {
    //    freopen("f.in","r",stdin);
    //    freopen("f.out","w",stdout);
        int n,x,mx=0;
        scanf("%d",&n);
        memset(d,0,sizeof(d));
        memset(d2,0,sizeof(d2));
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&x);
            T[x].r++;d2[x+x+x]+=2;
            mx=max(mx,x);
        }
        T[0].r=1;FFT1(mx,mx);
        T[0].r=0;FFT2(mx,mx);
        FFT3(mx*2,mx);
        return 0;
    }
  • 相关阅读:
    04 16 团队竞技(第二场) 赛后总结
    HDU 1863 畅通工程 克鲁斯卡尔算法
    HUD 2544 最短路 迪杰斯特拉算法
    hdoj 4526 威威猫系列故事——拼车记
    HDU 3336 Count the string 查找匹配字符串
    Linux command line exercises for NGS data processing
    肿瘤基因组学数据库终结者:cBioPortal---转载
    lncRNA研究利器之"TANRIC"
    Python的collections模块中的OrderedDict有序字典
    python set
  • 原文地址:https://www.cnblogs.com/AKCqhzdy/p/8011044.html
Copyright © 2011-2022 走看看