zoukankan      html  css  js  c++  java
  • 2016 acm香港网络赛 A题. A+B Problem (FFT)

     

    原题地址:https://open.kattis.com/problems/aplusb

    FFT代码参考kuangbin的博客:http://www.cnblogs.com/kuangbin/archive/2013/07/24/3210565.html

     

    A+B Problem

    Given N integers in the range [−50000,50000], how many ways are there to pick three

    integers ai, aj, ak, such that i, j, k are pairwise distinct and ai+aj=ak? Two ways

    are different if their ordered triples (i,j,k)of indices are different.

    Input

    The first line of input consists of a single integer N

    (1≤N≤200000). The next line consists of N space-separated integers a1,a2,…,aN

    Output

    Output an integer representing the number of ways.

    Sample Input 1

                         Sample Output 1

    4

    1 2 3 4

    4

     

    Sample Input 2

                         Sample Output 2

    6

    1 1 3 3 4 6

    10

    Author(s): Tung Kam Chuen

    Source: Hong Kong Regional Online Preliminary 2016

     

    题意:给一个数列,从中选三个数 ai, aj, ak,使得ai+aj=ak,问共有多少组( i, j, k)满足条件。

    其实就是FFT。

    注意一下a数组的数据范围,a[i]可能为负数,所有a[i]+50000,把负数转化为正数处理;

    如果数组里有0,先把0删掉,最后特殊处理。

    把a数组转化成num数组,num[i]表示i出现的次数。

    然后num数组和num数组卷积,得到新的num数组。

    num数组意义:num[x]表示使ai+aj=x,(i,j)的取法有多少种。

    #include <algorithm>
    #include <cstring>
    #include <string.h>
    #include <iostream>
    #include <list>
    #include <map>
    #include <set>
    #include <stack>
    #include <string>
    #include <utility>
    #include <vector>
    #include <cstdio>
    #include <cmath>
    
    #define LL long long
    #define N 200005
    #define INF 0x3ffffff
    
    using namespace std;
    
    const double PI = acos(-1.0);
    
    
    struct Complex // 复数
    {
        double r,i;
        Complex(double _r = 0,double _i = 0)
        {
            r = _r; i = _i;
        }
        Complex operator +(const Complex &b)
        {
            return Complex(r+b.r,i+b.i);
        }
        Complex operator -(const Complex &b)
        {
            return Complex(r-b.r,i-b.i);
        }
        Complex operator *(const Complex &b)
        {
            return Complex(r*b.r-i*b.i,r*b.i+i*b.r);
        }
    };
    
    void change(Complex y[],int len) // 二进制平摊反转置换 O(logn)  
    {
        int i,j,k;
        for(i = 1, j = len/2;i < len-1;i++)
        {
            if(i < j)swap(y[i],y[j]); 
            k = len/2;
            while( j >= k)
            {
                j -= k;
                k /= 2;
            }
            if(j < k)j += k;
        }
    }
    void fft(Complex y[],int len,int on) //DFT和FFT
    {
        change(y,len);
        for(int h = 2;h <= len;h <<= 1)
        {
            Complex wn(cos(-on*2*PI/h),sin(-on*2*PI/h));
            for(int j = 0;j < len;j += h)
            {
                Complex w(1,0);
                for(int k = j;k < j+h/2;k++)
                {
                    Complex u = y[k];
                    Complex t = w*y[k+h/2];
                    y[k] = u+t;
                    y[k+h/2] = u-t;
                    w = w*wn;
                }
            }
        }
        if(on == -1)
            for(int i = 0;i < len;i++)
                y[i].r /= len;
    }
    
    
    const int M =50000;          // a数组所有元素+M,使a[i]>=0
    const int MAXN = 800040;
    
    Complex x1[MAXN];
    int a[MAXN/4];                //原数组
    long long num[MAXN];     //利用FFT得到的数组
    long long tt[MAXN];        //统计数组每个元素出现个数
    
    int main()
    {
        int n=0;                   // n表示除了0之外数组元素个数
        int tot;
        scanf("%d",&tot);
        memset(num,0,sizeof(num));
        memset(tt,0,sizeof(tt));
    
        int cnt0=0;             //cnt0 统计0的个数
        int aa;
    
        for(int i = 0;i < tot;i++)
            {
                scanf("%d",&aa);
                if(aa==0) {cnt0++;continue;}  //先把0全删掉,最后特殊考虑0
                else a[n]=aa;  
                num[a[n]+M]++;
                tt[a[n]+M]++;
                n++;
            }
    
        sort(a,a+n);
        int len1 = a[n-1]+M+1;
        int len = 1;
    
        while( len < 2*len1 ) len <<= 1;
    
        for(int i = 0;i < len1;i++){
             x1[i] = Complex(num[i],0);
        }
        for(int i = len1;i < len;i++){
             x1[i] =Complex(0,0);
        }
        fft(x1,len,1);
    
        for(int i = 0;i < len;i++){
            x1[i] = x1[i]*x1[i];
        }
        fft(x1,len,-1);
    
        for(int i = 0;i < len;i++){
             num[i] = (long long)(x1[i].r+0.5);
        }
    
        len = 2*(a[n-1]+M);
            
        for(int i = 0;i < n;i++) //删掉ai+ai的情况
               num[a[i]+a[i]+2*M]--;
    /*
       for(int i = 0;i < len;i++){
                if(num[i]) cout<<i-2*M<<' '<<num[i]<<endl;
        }
    */
        long long ret= 0;
    
        int l=a[n-1]+M;
    
        for(int i = 0;i <=l; i++)   //ai,aj,ak都不为0的情况
            {
                if(tt[i]) ret+=(long long)(num[i+M]*tt[i]);
            }
    
        ret+=(long long)(num[2*M]*cnt0);        // ai+aj=0的情况
    
        if(cnt0!=0)
            {
                if(cnt0>=3) {                   //ai,aj,ak都为0的情况
                    long long tmp=1;
                    tmp*=(long long)(cnt0);
                    tmp*=(long long)(cnt0-1);
                    tmp*=(long long)(cnt0-2);
                    ret+=tmp;
                }
                 for(int i = 0;i <=l; i++)
                    {
                        if(tt[i]>=2){             // x+0=x的情况      
                            long long tmp=(long long)cnt0;
                            tmp*=(long long)(tt[i]);
                            tmp*=(long long)(tt[i]-1);
                            ret+=tmp*2;
                        }
                    }
            }
    
        printf("%lld
    ",ret);
    
        return 0;
    }
  • 相关阅读:
    jQueryrocket
    jQueryrocket
    jQueryrocket
    jQueryrocket
    jQueryrocket
    SPListItem.UpdateOverwriteVersion()真的不会创建新版本吗?
    不能访问本地服务器场。没有注册带有FeatureDependencyId 的 Cmdlet
    SharePoint 2013 另一个程序正在使用此文件,进程无法访问。 (异常来自 HRESULT:0x80070020)
    使用PowerShell修改操作系统“环境变量”
    无法解决“Microsoft.SharePoint.Security, Version=15.0.0.0,”与“Microsoft.SharePoint.Security, Version=14.0.0.0”之间的冲突
  • 原文地址:https://www.cnblogs.com/smartweed/p/5860251.html
Copyright © 2011-2022 走看看