zoukankan      html  css  js  c++  java
  • 【BZOJ3771】 Triple

    Triple

    题目大意

    给你一堆有价值的物品,可以选择其中的一个、两个或者三个,不能重复选,求可以选出来的总价值以及方案数。最大价值在FFT范围内。

    Solution

    FFT+容斥

    一个多项式的系数是方案数,指数就是价值,这里一个多项式(A[x])代表多项式A的x次方项

    那么我们把两个多项式乘起来,就可以得到一边选一个元素,另一边也选一个元素加起来的方案数

    原理:多项式乘法,两项相乘,指数相加,系数相乘,相当于价值相加,方案数相乘

    所以我们建立三个多项式,分别存某种物品选一个、两个、三个的价值数目

    设为a,b,c,则当一个物品价值为x时,(a[x]++),(b[x+x]++),(c[x+x+x]++)

    那么对于每种价值i,分三类情况:

    1、只选一个,此时答案显然就是(a[i])

    2、选两个,此时不去重答案是(a[i]^2),但是其中会有两个一样的情况,然后去掉顺序,所以最终答案是((a[i]^2-b[i]) over 2)

    3、选三个,此时不去重答案是(a[i]^3),去掉(x,x,x)与(x,y,y)、(y,x,y)、(y,y,x)的情况,就要减掉(a[i] imes b[i] imes 3),但是这样多减去了两个(x,x,x),所以要加回来(c[i] imes 2)

    最终答案是((a[i]^3-(a[i] imes b[i] imes 3)+(c[i] imes 2)) over 6)

    code:

    #include<bits/stdc++.h>
    using namespace std;
    struct comp{
        double x,y;
        comp (double xx=0,double yy=0){
            x=xx,y=yy;
        }
    }a[200010],b[200010],c[200010],ans[200010];
    comp operator +(comp a,comp b){return comp(a.x+b.x,a.y+b.y);}
    comp operator -(comp a,comp b){return comp(a.x-b.x,a.y-b.y);}
    comp operator *(comp a,comp b){return comp(a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x);}
    comp operator *(comp a,double b){return comp(a.x*b,a.y*b);}
    int rev[200010];
    int lim=1;
    const double pi=acos(-1);
    void fft(comp *A,int type){
        for(int i=0;i<lim;++i){
            if(i<rev[i])swap(A[i],A[rev[i]]);
        }
        for(int mid=1;mid<lim;mid<<=1){
            comp wn=comp(cos(pi/mid),type*sin(pi/mid));
            for(int j=0,R=mid<<1;j<lim;j+=R){
                comp w=comp(1,0);
                for(int k=0;k<mid;++k,w=w*wn){
                    comp x=A[j+k],y=w*A[j+k+mid];
                    A[j+k]=x+y;
                    A[j+k+mid]=x-y;
                }
            }
        }
        if(type==-1){
        	for(int i=0;i<lim;++i)A[i].x/=lim;
    	}
    }
    int main(){
        int n;
        scanf("%d",&n);
        int len=0;
        for(int i=1;i<=n;++i){
            int x;
            scanf("%d",&x);
            a[x].x+=1.0,b[x*2].x+=1.0,c[x*3].x+=1.0;
            len=max(len,x*3);
        }
    	int tmp=0;
        while(lim<=len){
            lim<<=1,tmp++;
        }
        //cout<<lim<<" "<<tmp<<endl;
        for(int i=0;i<=lim;++i){
            rev[i]=rev[i>>1]>>1|(i&1)<<(tmp-1);
        }
        fft(a,1);
        fft(b,1);
        fft(c,1);
        for(int i=0;i<lim;++i){
            ans[i]=a[i];
    		ans[i]=ans[i]+(a[i]*a[i]-b[i])*0.5;
    		ans[i]=ans[i]+(a[i]*a[i]*a[i]-b[i]*a[i]*3.0+c[i]*2.0)*(1.0/6.0);
        }
        fft(ans,-1);
        for(int i=0;i<lim;++i){
            int num=ans[i].x+0.5;
            if(num){
                printf("%d %d
    ",i,num);
            }
        }
    }
    
  • 相关阅读:
    <转>lua 调用 C函数
    <转>VC之获取CPU序列号
    <转> 求结构体偏移
    借助 FireBug 进行轻量级代码自动生成。
    内存盘配置IIS临时目录
    导出带有复合表头的Excel方案.
    左右互博之精简代码
    [转]JavaScript 秘密花园
    MVC中,Ajax Post 数组的实现方案
    Sql 存储过程 参数传递空字符串, 到SQL 端变成了 空格!!
  • 原文地址:https://www.cnblogs.com/youddjxd/p/11613122.html
Copyright © 2011-2022 走看看