• Gym 100783C Golf Bot FFT


    大致题意:

    给你N个整数和M个整数,问这M个数中,有几个数可以表达成那N个整数中一个或者两个整数的和。

    分析:

    算是半个裸的FFT。FFT可以用来在nlongn时间内求高精度乘法,我们先模拟一下乘法。

    A4A3A2A1A0*B4B3B2B1B0  Ai,Bj表示位数,结果保存在Ck中

     4   3   2   1   0(下标)

    A4 A3 A2 A1 A0

    B4 B3 B2 B1 B0

    先不考虑进位

    那么C0=A0*B0

           C1=A0*B1+A1*B0

           Ck=sum(Ai*Bj) (i+j=k)

    我们现在看题目是求两个数或者一个数的和是否能在M中匹配到。与上式对比,发现了共同点,i,j的和的下标对应的值即Ck,也就是说我们可以把出现的数字当做位置,出现的位置赋值为1,没有为0,第0位为1,因为可以加0嘛。

    样例如下

           5 4 3 2 1 0(下标)

           1 0 1 0 1 1

      X            1 0 1 0 1 1

    =  1 0 2 0 3 2 2 2 1 2 1

        A 9 8 7 6 5 4 3 2 1 0(下标)

    结果不需要再进位,只要k下标对应的值大于0就符合条件。

    #include <bits/stdc++.h>
    using namespace std;
    
    const double PI = acos(-1.0);
    struct Complex
    {
        double x, y;
        Complex(double _x = 0.0, double _y = 0.0)
        {
            x = _x;
            y = _y;
        }
        Complex operator - (const Complex &b)const
        {
            return Complex(x-b.x, y-b.y);
        }
        Complex operator + (const Complex &b)const
        {
            return Complex(x+b.x, y+b.y);
        }
        Complex operator * (const Complex &b)const
        {
            return Complex(x*b.x-y*b.y, x*b.y+y*b.x);
        }
    };
    
    void change(Complex y[], int len)
    {
        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)
    {
        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].x /= len;
    }
    
    const int maxn=4*200010;
    Complex x1[maxn],x2[maxn];
    int a[maxn/4];
    int sum[maxn];
    
    int main()
    {
        int N,M;
        while(~scanf("%d",&N))
        {
            memset(a,0,sizeof(a));
            int len1=0;
            for(int i=0; i<N; i++)
            {
                int tmp;
                scanf("%d",&tmp);
                a[tmp]=1;
                len1=max(len1,tmp);
            }
            len1++;
            int len=1;
            while(len < len1*2) len<<=1;
            a[0]=1;
            for(int i=0; i<len1; i++)
                x1[i]=Complex(a[i],0);
            for(int i=0; i<len1; i++)
                x2[i]=Complex(a[i],0);
            for(int i=len1; i<len; i++)
                x2[i]=Complex(0,0);
            fft(x1,len,1);
            fft(x2,len,1);
            for(int i=0; i<len; i++)
                x1[i]=x1[i]*x2[i];
            fft(x1,len,-1);
            for(int i=0; i<len; i++)
                sum[i]=(int)(x1[i].x+0.5);
            scanf("%d",&M);
            len=2*len1-1;
            int cnt=0;
            for(int i=0;i<M;i++)
            {
                int t;
                scanf("%d",&t);
                if(sum[t]>0) cnt++;
            }
            printf("%d
    ",cnt);
        }
        return 0;
    }
  • 相关阅读:
    中缀表达式求值
    520的信心赛——点点玩deeeep
    520的信心赛——麓麓学数学
    l洛谷 (水题)P4144 大河的序列
    洛谷 P3391 【模板】文艺平衡树(Splay)
    在洛谷3369 Treap模板题 中发现的Splay详解
    洛谷 P1344 [USACO4.4]追查坏牛奶Pollutant Control
    洛谷 P1678 烦恼的高考志愿
    洛谷 P2421 A-B数对(增强版)
    P3381 【模板】最小费用最大流
  • 原文地址:https://www.cnblogs.com/pach/p/6914291.html
Copyright © 2020-2023  润新知