hihoCoder 1388(fft)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了hihoCoder 1388(fft)相关的知识,希望对你有一定的参考价值。

让你求(a[i] - b[(i + x) % n]) ^ 2的最大值,其中x从0到n-1。

因为结果总是sum(a[i] ^ 2) + sum(b[i] ^ 2) - sum(2 * a[i] * b[(i + x) % n])。

因此只需要找到最小的sum(2 * a[i] * b[(i + x) % n])即可。

据此我们构造两个向量。

a = (a[n - 1], a[n - 2], ... , a[1], a[0], a[n - 1], a[n - 2], ... , a[2], a[1])

b = (b[0], b[1], ... , b[n - 2], b[n - 1])

可以看出要求sum的最小值就是求ab的卷积从n-1到2 * n - 2的最小值(下标从0开始)。

因此用fft可以求出卷积,再找一遍最小值,记住偏移量,根据偏移量计算结果就ok

技术分享
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <string>
#include <cmath>
using namespace std;
const int maxn = 240005;
const double PI = acos(-1.0);
struct Complex
{
    double x, y;
    Complex(double x = 0, double y = 0) : x(x), y(y) { }
    Complex operator + (const Complex &rhs)
    {
        return Complex(x + rhs.x, y + rhs.y);
    }
    Complex operator - (const Complex &rhs)
    {
        return Complex(x - rhs.x, y - rhs.y);
    }
    Complex operator * (const Complex &rhs)
    {
        return Complex(x * rhs.x - y * rhs.y, x * rhs.y + y * rhs.x);
    }
}a[maxn], b[maxn];
long long num1[maxn], num2[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;
}
int main()
{
    int T;
    scanf("%d", &T);
    while(T--)
    {
        int n;
        scanf("%d", &n);
        for(int i = 0; i < n; ++i)
        {
            scanf("%lld", &num1[i]);
            a[n - i - 1].x = num1[i];
            a[n - i - 1].y = 0;
        }
        for(int i = n; i < 2 * n - 1; ++i)
        {
            a[i].x = a[i - n].x;
            a[i].y = 0;
        }
        for(int i = 0; i < n; ++i)
        {
            scanf("%lld", &num2[i]);
            b[i].x = num2[i];
            b[i].y = 0;
        }
        int tmp = 1;
        while(tmp < 2 * n - 1) tmp <<= 1;
        for(int i = 2 * n - 1; i < tmp; ++i)
        {
            a[i].x = a[i].y = 0;
        }
        for(int i = n; i < tmp; ++i)
        {
            b[i].x = b[i].y = 0;
        }
        fft(a, tmp, 1);
        fft(b, tmp, 1);
        for(int i = 0; i < tmp; ++i)
            a[i] = a[i] * b[i];
        fft(a, tmp, -1);
        double MAX = -1;
        int pos = -1;
        for(int i = n - 1; i < 2 * n - 1; ++i)
        {
            if(a[i].x > MAX)
            {
                MAX = a[i].x;
                pos = i;
            }
        }
        pos = pos - n + 1;
        long long ans = 0;
        for(int i = 0; i < n; ++i)
        {
            ans += (num1[i] - num2[(i + pos) % n]) * (num1[i] - num2[(i + pos) % n]);
        }
        printf("%lld\n", ans);
    }
    return 0;
}
View Code

以上是关于hihoCoder 1388(fft)的主要内容,如果未能解决你的问题,请参考以下文章

hihocoder #1388 : Periodic Signal NTT&FFT

hihoCoder 1388(fft)

Hihocoder1388 2016年北京网络赛 FFT

hihocode #1388 : Periodic Signal NTT

hihoCoder1388 Periodic Signal(2016北京网赛F:NTT)

hihocoder 1388 Periodic Signal