HihoCoder1388(Periodic Signal)-fft(快速傅里叶变换)

来源:互联网 发布:qq 微信 知乎 编辑:程序博客网 时间:2024/05/17 09:31

题目链接:Periodic Signal


题意:求


思路:


求题目所给的最小值转化为了求的最大值。


构造序列两个


求这两个序列的卷积,就可以得到,k = 0, 1, 2, ..., n - 1,

求卷积用fft来实现,复杂度为o(n*log(n))


由于用fft算出来的数精度误差会比较大,可以用这个方法先算出k的位置,然后将k代入原始式子,求得答案。


代码:

# pragma comment(linker, "/STACK:1024000000,1024000000")# include <iostream># include <algorithm># include <cstdio># include <cstring># include <cmath>using namespace std;typedef long long ll;const long double PI = acos(-1.0);const int maxn = 5e5 + 5;int a[maxn], b[maxn];int n;struct Complex {    long double x, y;    Complex() : x(0.0), y(0.0) { }    Complex(long double x, long double y) : 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);    }} A[maxn], B[maxn];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;}ll sqr(ll x) {    return x * x;}int main(void){    int T; scanf("%d", &T);    while (T-- && scanf("%d", &n)) {        for (int i = 0; i < n; ++i) {            scanf("%d", a + i);            A[i] = Complex(a[i] * 1.0, 0.0);        }        for (int i = 0; i < n; ++i) {            scanf("%d", b + i);            B[n - i - 1] = Complex(b[i] * 1.0, 0.0);        }        for (int i = n; i < n * 2; ++i) B[i] = B[i - n], A[i] = Complex(0.0, 0.0);        n *= 2;        int len = 1;        while (len < n) len <<= 1;        len <<= 1;        for (int i = n; i < len; ++i) A[i] = B[i] = Complex(0.0, 0.0);        fft(A, len, 1); fft(B, len, 1);        for (int i = 0; i < len; ++i) A[i] = A[i] * B[i];        fft(A, len, -1);        int k = 0;        long double Max = A[n * 2 - 1].x;        n /= 2;        for (int i = n * 2 - 2; i >= n; --i) {            if (Max < A[i].x) {                Max = A[i].x; k = n * 2 - i - 1;            }        }        ll ans = 0;        for (int i = 0; i < n; ++i) {            ans += sqr(a[i] - b[(i + k) % n]);        }        printf("%lld\n", ans);    }    return 0;}


原创粉丝点击