• BZOJ 2194 [快速傅里叶变换 卷积]


     


     题意:请计算C[k]=sigma(a[i]*b[i-k]) 其中 k < = i < n ,并且有 n < = 10 ^ 5。 a,b中的元素均为小于等于100的非负整数。


    卷积 (f x g)(n)=∑{f(i)*g(n-i):i=0...n}
    
    多项式乘法就是一个系数向量的卷积
    
    可以用FFT快速计算卷积
    
    遇到和不是定值的情况可以反转一个向量
    
    如本题反转a向量后
    
      c[k]=∑(a[n-i-1]*b[i-k]) k<=i<=n-1
    
    更换求和指标 i=i-k
    
      c[k]=∑(a[n-i-k-1]*b[i]) 0<=i<=n-k-1-k-1消去,令t=n-k-1
    
      c[n-t-1]=∑(a[t-i]*b[i]) 0<=i<=t
    
    这样就是标准的卷积形式啦
    以前的推导

    [update 2017-03-30]

    重做了一下

    反转一个向量,变成和为常数的形式

    $ c_k = sumlimits_{i=k}^{n-1} a_i b_{n-1-i+k} = d_{n+k-1} $

    这样计算d是没问题的,因为a和b只有$0...n-1$非0,其他都是0

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    using namespace std;
    typedef long long ll;
    const int N=(1<<18)+5, INF=1e9;
    const double PI=acos(-1);
    inline int read(){
        char c=getchar();int x=0,f=1;
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
        return x*f;
    }
    
    struct meow{
        double x, y;
        meow(double a=0, double b=0):x(a), y(b){}
    };
    meow operator +(meow a, meow b) {return meow(a.x+b.x, a.y+b.y);}
    meow operator -(meow a, meow b) {return meow(a.x-b.x, a.y-b.y);}
    meow operator *(meow a, meow b) {return meow(a.x*b.x-a.y*b.y, a.x*b.y+a.y*b.x);}
    meow conj(meow a) {return meow(a.x, -a.y);}
    typedef meow cd;
    
    struct FFT{
        int n, rev[N];
        void ini(int lim) {
            n=1; int k=0;
            while(n<lim) n<<=1, k++;
            for(int i=0; i<n; i++) {
                int t=0;
                for(int j=0; j<k; j++) if(i&(1<<j)) t |= (1<<(k-1-j));
                rev[i]=t;
            }
        }
        void dft(cd *a, int flag) {
            for(int i=0; i<n; i++) if(i<rev[i]) swap(a[i], a[rev[i]]);
            for(int l=2; l<=n; l<<=1) {
                int m=l>>1; 
                cd wn = meow(cos(2*PI/l), flag*sin(2*PI/l));
                for(cd *p=a; p!=a+n; p+=l) {
                    cd w(1, 0);
                    for(int k=0; k<m; k++) {
                        cd t = w*p[k+m];
                        p[k+m] = p[k] - t;
                        p[k] = p[k] + t;
                        w=w*wn;
                    }
                }
            }
            if(flag==-1) for(int i=0; i<n; i++) a[i].x/=n;
        }
        void mul(cd *a, cd *b, int lim) {
            ini(lim);
            dft(a, 1); dft(b, 1);
            for(int i=0; i<n; i++) a[i]=a[i]*b[i];
            dft(a, -1);
        }
    }f;
    
    int n;
    cd a[N], b[N];
    int main() {
        freopen("in","r",stdin);
        n=read();
        for(int i=0; i<n; i++) a[i].x=read(), b[n-1-i].x=read();
        f.mul(a, b, n+n-1);
        for(int i=n-1; i<2*n-1; i++) printf("%d
    ", int(a[i].x+0.5));
    }
  • 相关阅读:
    如何查看存储过程中动态生成的sql
    [原] 高淇Java300集系列笔记 (待续)
    [原] 在HTML文档中添加标签名、ID、类名
    jquery学习笔记1-Ajax跨站请求资源
    博客搬家啦。请访问我的新底盘www.boyipark.com
    web端跨域调用webapi
    遮罩层
    去掉字符串后最后一个 ","
    对JAVA的static深刻理解(结合C语言的思考)
    java事件响应方法汇总(容器类监听、监听器类、AbstractAction、反射)
  • 原文地址:https://www.cnblogs.com/candy99/p/6388946.html
Copyright © 2020-2023  润新知