zoukankan      html  css  js  c++  java
  • [BZOJ3771] Triple

    Description

    有个沙雕樵夫有n把价值互不相同的斧头,某天一个沙雕水神偷走了这个樵夫的一把或两把或三把斧头。樵夫的总损失值就是被偷走的斧头价值和。他想知道对于每个可能的总损失,有几种可能的方案。

    注意:如果水神拿走了两把斧头a和b,(a,b)和(b,a)算一种方案。拿走三把斧头时,(a,b,c),(b,c,a),(c,a,b),(c,b,a),(b,a,c),(a,c,b)也只算一种方案。

    a_i<=40000。

    Solution

    这沙雕题面还真是悲伤啊哈哈哈哈哈哈

    可以搞出一个生成函数(总觉得就是个桶),就是拿走一个斧头的方案数f(x)

    两个数的方案数就是(f*f)(x),但是其中包含了两次使用同一个数的方案数h(x)=f(2x),而其余的方案数统计了两次,所以方案数为(f*f-h)(x)/2

    三个数的方案数就是(f*f*f)(x),然后减去三次使用同一个数的方案数g(x)=f(3x),再减去两次使用同一个数的方案数(f*h-g)(x)*3 (里面减掉g是因为三次使用同一个数的方案数被重复计算,再乘3是因为在(f*f*f)(x)中计算了三次((x,x,y),(x,y,x),(y,x,x)),而其余的方案统计了6次,所以方案数为(f*f*f-3*h*f+2*g)(x)/6

    总感觉在点值表达那里直接乘起来解释不通所以我是在系数表达那块才乘起来的

    还有FFT的空间开几倍是个玄学问题

    Code

    还是改掉了namespace码风因为实在是太鬼畜了

    #include<bits/stdc++.h>
    using std::min;
    using std::max;
    using std::swap;
    using std::vector;
    typedef double db;
    typedef long long ll;
    #define pb(A) push_back(A)
    #define pii std::pair<int,int>
    #define all(A) A.begin(),A.end()
    #define mp(A,B) std::make_pair(A,B)
    const int N=5e5+5;
    const db Pi=acos(-1);
    
    int n,lim,rev[N],val[N],s[N];
    
    struct cp{
        db x,y;
        cp (db a=0,db b=0){x=a,y=b;}
        friend cp operator+(cp a,cp b){return cp(a.x+b.x,a.y+b.y);}
        friend cp operator-(cp a,cp b){return cp(a.x-b.x,a.y-b.y);}
        friend cp operator*(cp a,cp b){return cp(a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x);}
    }f[N],f2[N],f3[N],h[N],g[N],hf[N];
    
    int getint(){
        int X=0,w=0;char ch=getchar();
        while(!isdigit(ch))w|=ch=='-',ch=getchar();
        while( isdigit(ch))X=X*10+ch-48,ch=getchar();
        if(w) return -X;return X;
    }
    
    void fft(cp *f,int opt){
        for(int i=0;i<lim;i++) if(i<rev[i]) swap(f[i],f[rev[i]]);
        for(int mid=1;mid<lim;mid<<=1){
            cp tmp=cp(cos(Pi/mid),sin(Pi/mid)*opt);
            for(int R=mid<<1,l=0;l<lim;l+=R){
                cp w=cp(1,0);
                for(int k=0;k<mid;k++,w=w*tmp){
                    cp x=f[l+k],y=f[l+k+mid]*w;
                    f[l+k]=x+y,f[l+k+mid]=x-y;
                }
            }
        }
    }
    
    signed main(){
        n=getint();int mx=0;
        for(int i=1;i<=n;i++) val[i]=getint(),s[val[i]]++,mx=max(mx,val[i]),f[val[i]].x++,h[val[i]*2].x++,g[val[i]*3].x++;
        lim=1;while(lim<=4*mx) lim<<=1;
        for(int i=1;i<lim;i++) rev[i]=(rev[i>>1]>>1)|(i&1?lim>>1:0);
        fft(f,1),fft(h,1);
        for(int i=0;i<lim;i++) hf[i]=h[i]*f[i],f2[i]=f[i]*f[i],f3[i]=f[i]*f[i]*f[i];
        fft(hf,-1),fft(f,-1),fft(f2,-1),fft(f3,-1),fft(h,-1);
        for(int i=0;i<lim;i++){
            int x=(int)(f[i].x/lim+0.5)+((int)(f2[i].x/lim+0.5)-(int)(h[i].x/lim+0.5))/2+((int)(f3[i].x/lim+0.5)-(int)(hf[i].x/lim+0.5)*3+g[i].x*2)/6;
            if(x) printf("%d %d
    ",i,x);
        } return 0;
    }
    
    
  • 相关阅读:
    旋转坐标转换的矩阵推导
    Union的妙用和注意
    OpenGL环境搭建Windows+Mac+Linux
    RichLabel基于Cocos2dx+Lua v3.x
    Cocos2dx+lua中Color参数的坑
    常见开源协议
    lua序列化(支持循环引用)
    lua标签解析器
    Markdown基本语法
    python3爬取墨迹天气并发送给微信好友,附源码
  • 原文地址:https://www.cnblogs.com/YoungNeal/p/10106650.html
Copyright © 2011-2022 走看看