zoukankan      html  css  js  c++  java
  • Spoj 8372 Triple Sums

    题意:给你n个数字,对于任意s,s满足(s=u_i+u_j+u_k,i<j<k),要求出所有的s和对应满足条件的i,j,k的方案数

    Solution:

    构造一个函数:(A(x)=sum_{i=0}^{n-1}a_ix^i),这是一个多项式

    对于每一个(u_i),我们把这个多项式中的(x^{u_i})的系数(a_{u_i})加上一

    也就是说,对于任意(x^i),它的系数为i在给出序列中出现的次数

    多项式的三次方为:

    [C(x)=A(x)^3\ C(x)=sum_{i=0}^{3n}c_ix^i\ c_i=sum_{0le l,j,kle n,l+j+k=i}a_ja_ka_l ]

    在不考虑(i<j<k)的限制条件下,对于任意s,构成s的方案数就是(C(x))(x^s)的系数(c_s)

    我们再来考虑容斥去重将不符合要求的方案给去掉

    考虑当(i,j,k)中有两个数相同时,构建多项式:(B(x)=sum_{i=0}^{n-1}b_ix^i)

    其中对于任意(x^i),它的系数(b_i)(i/2(i\,mod\,2=0))在序列中出现的次数

    则对于多项式:(D(x)=A(x)B(x)),它的系数就是两数相同的情况的方案数

    (C(x))中它被多加了三次,但减去之后,我们显然可以发现我们将(i=j=k)的情况多减了一次

    加上后,就得到了不考虑(i<j<k)时,(i e j e k)的所有方案数,此时再考虑(ile jle k),只需把方案数除以6就行了

    Code:

    #include<bits/stdc++.h>
    #define ll long long
    #define Pi acos(-1.0)
    using namespace std;
    const int N=1<<17;
    int n,len,tim=17,rtt[N],c[N];
    struct cp{double x,y;}aa[N],bb[N],cc[N];
    cp operator + (cp a,cp b){return (cp){a.x+b.x,a.y+b.y};}
    cp operator - (cp a,cp b){return (cp){a.x-b.x,a.y-b.y};}
    cp operator * (cp a,cp b){return (cp){a.x*b.x-a.y*b.y,a.y*b.x+a.x*b.y};}
    void FFT(cp *a,int flag){
        for(int i=0;i<len;i++)
            if(i<rtt[i]) swap(a[i],a[rtt[i]]);
        for(int l=2;l<=len;l<<=1){
            cp wn=(cp){cos(flag*2*Pi/l),sin(flag*2*Pi/l)};
            for(int st=0;st<len;st+=l){
                cp w=(cp){1,0};
                for(int u=st;u<st+(l>>1);u++,w=w*wn){
                    cp x=a[u],y=w*a[u+(l>>1)];
                    a[u]=x+y,a[u+(l>>1)]=x-y;
                }
            }
        }
    }
    int read(){
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
        while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
        return x*f;
    }
    int main(){
    	n=read(),len=N;
    	for(int i=1;i<=n;i++){
    		int x=read()+20000;
    		aa[x].x=aa[x].x+1;
    		bb[x<<1].x=bb[x<<1].x+1;
    		c[x+x+x]++;
    	}
        for(int i=0;i<len;i++)
            rtt[i]=(rtt[i>>1]>>1)|((i&1)<<(tim-1));
        FFT(aa,1);FFT(bb,1);
        for(int i=0;i<len;i++)
        	cc[i]=aa[i]*(aa[i]*aa[i]-(cp){3,0}*bb[i]);
    	FFT(cc,-1);
        for(int i=0;i<N;i++){
    		ll cnt=((ll){cc[i].x/len+0.5}+2*c[i])/6;
    		if(cnt) printf("%d : %lld
    ",i-60000,cnt);
    	}
        return 0;
    }
    
  • 相关阅读:
    DROP,TRUNCATE 和DELETE的区别
    工作手记之Cransoft
    Java输入输出流
    上海植物园
    eclipse中开发android程序时,打开layout配置文件eclipse关闭
    Android SDK 2.2 开发环境搭建
    Android读取电话薄中的电话号码
    Android模拟器大小
    工作手记之Cransoft(二)
    工作手记之Cransoft(三)
  • 原文地址:https://www.cnblogs.com/NLDQY/p/10758961.html
Copyright © 2011-2022 走看看