SPOJ TSUM Triple Sums(FFT+生成函数+容斥原理)

TSUM - Triple Sums

no tags 

You're given a sequence s of N distinct integers.
Consider all the possible sums of three integers from the sequence at three different indicies.
For each obtainable sum output the number of different triples of indicies that generate it.

Constraints:

N <= 40000, |si| <= 20000

Input

The first line of input contains a single integer N.
Each of the next N lines contain an element of s.

Output

Print the solution for each possible sum in the following format:
sum_value : number_of_triples

Smaller sum values should be printed first.

Example

Input:

5
-1
2
3
0
5
Output:

1 : 1
2 : 1
4 : 2
5 : 1
6 : 1
7 : 2
8 : 1
10 : 1

Explanation:
4 can be obtained using triples ( 0, 1, 2 ) and ( 0, 3, 4 ).
7 can be obtained using triples ( 0, 2, 4 ) and ( 1, 3, 4 ).

Note: a triple is considered the same as any of its permutations. 


        大致题意:给你N个数字,然后从中任意挑选三个数字并求和,让你输出和的所以可能以及对应取到每个和的方案数。
        由于是加法,考虑用生成函数,两个生成函数相乘可以得到任意两个项相加的和,三个也是一样。由于|si| <=20000,因此首先把si整体扩大20000防止出现负数。令A为对应的生成函数,我们可以发现,A*A*A的结果回出现重复。A*A*A=三个数字一样+其中两个数字一样+三个数字不相同。于是考虑容斥,减去重复的。令A*A*A表示总体,B表示取两个相同数字,那么A*B= 其中两个数字一样+三个数字不相同。再考虑容斥的系数,其中两个数字一样,这两个数字可以有三种位置组合,C(3,2)=3。因此答案要减去3*A*B。目前答案是A*A*A-3*A*B。我们发现三个数字不相同的被少计算了两次,于是补回来,用C表示取三个相同数字,答案就变成了A*A*A-3*A*B+2*C。现在就能够保证三个数字不相同,但是三个不同数字的组合有3!种,所以最后答案还要除以6。具体见代码:
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define LL long long
#define N 1<<17
#define PI acos(-1.0)
using namespace std;

namespace FFT
{
    struct Complex
    {
        double r,i;
        Complex(double real=0.0,double image=0.0)
        {
            r=real; i=image;
        }
        Complex operator + (const Complex o)
        {
            return Complex(r+o.r,i+o.i);
        }
        Complex operator - (const Complex o)
        {
            return Complex(r-o.r,i-o.i);
        }
        Complex operator * (const Complex o)
        {
            return Complex(r*o.r-i*o.i,r*o.i+i*o.r);
        }
    };

    void brc(Complex *y, int l)
    {
        register int i,j,k;
        for( i = 1, j = l / 2; i < l - 1; i++)
        {
            if (i < j) swap(y[i], y[j]);
            k = l / 2; while ( j >= k) j -= k,k /= 2;
            if (j < k) j += k;
        }
    }

    void FFT(Complex *y, int len, double on)
    {
        register int h, j, k;
        Complex u, t; brc(y, len);
        for(h = 2; h <= len; h <<= 1)
        {
            Complex wn(cos(on * 2 * PI / h), sin(on * 2 * PI / h));
            for(j = 0; j < len; j += h)
            {
                Complex w(1, 0);
                for(k = j; k < j + h / 2; k++)
                {
                    u = y[k]; t = w * y[k + h / 2];
                    y[k] = u + t; y[k + h / 2] = u - t;
                    w = w * wn;
                }
            }
        }
        if (on<0) for (int i = 0; i < len; i++) y[i].r/=len;
    }

}

FFT::Complex A[N],B[N],C[N],ans[N];

int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);
    int n; cin>>n;
    for(int i=1;i<=n;i++)
    {
        int x;
        cin>>x;
        x+=20000;
        A[x].r++;
        B[x+x].r++;
        C[x+x+x].r++;
    }
    FFT::FFT(A,N,1);
    FFT::FFT(B,N,1);
    for(int i=0;i<N;i++)
        ans[i]=A[i]*(A[i]*A[i]-B[i]-B[i]-B[i]);
    FFT::FFT(ans,N,-1);
    for(int i=0;i<N;i++)
    {
        LL res=((LL)(ans[i].r+0.5)+2*C[i].r)/6;
        if (res>0) cout<<i-60000<<" : "<<res<<endl;
    }
    return 0;
}

        

猜你喜欢

转载自blog.csdn.net/u013534123/article/details/80180724
今日推荐