1. 程式人生 > >bzoj 4827: [HNOI2017]禮物 (FFT)

bzoj 4827: [HNOI2017]禮物 (FFT)

main urn 直接 %d accepted lan real 有理 ==

一道FFT

然而據說暴力可以水70分

然而我省選的時候看到了直接嚇傻了 連暴力都沒打

太弱了啊QAQ

emmmm

詳細的拆開就看其他題解吧233

最後那一步卷積其實我一直沒明白

後來畫畫圖終於懂了

只要把其中一個反過來

多項式乘法的結果中的每一項系數就對應某一個Σx[i] * y[j] 的結果

前面幾項是不完全的結果

但是太小了就被忽略啦

代碼如下

/**************************************************************
    Problem: 4827
    User: cminus
    Language: C++
    Result: Accepted
    Time:5644 ms
    Memory:24568 kb
***************************************************************
*/ #include <cstdio> #include <cmath> #include <complex> using namespace std; const int N = 500100; typedef long long ll; typedef complex<double> cp; const double pi = acos(-1.0); cp A[N], B[N]; void FFT(cp *y, int n, int type) { if (n == 1) return ; cp l[n >> 1
], r[n >> 1]; for (int i = 0; i <= n; i++) if (i & 1) r[i >> 1] = y[i]; else l[i >> 1] = y[i]; FFT(l, n >> 1, type); FFT(r, n >> 1, type); cp omegan(cos(2 * pi / n), sin(2 * pi * type / n)), omega(1, 0); for (int i = 0; i < n >> 1
; i++) { y[i] = l[i] + r[i] * omega; y[i + (n >> 1)] = l[i] - r[i] * omega; omega *= omegan; } } int main() { int n, m, ans = 0, y = 0; scanf("%d %d", &n, &m); for (int i = 0; i < n; i++) { int x; scanf("%d", &x); A[n - i - 1] = x; ans += x * x; } for (int i = 0; i < n; i++) { int x; scanf("%d", &x); B[i] = x; ans += x * x; y += (int)B[i].real() - A[n - i - 1].real(); } int n1; for (n1 = 1; n1 <= n * 4; n1 <<= 1); for (int i = 0; i < n; i++) B[i + n] = B[i]; FFT(A, n1, 1); FFT(B, n1, 1); for (int i = 0; i <= n1; i++) A[i] *= B[i]; FFT(A, n1, -1); int temp = 0, z = (-y) / n; for (int i = 0; i < n; i++) temp = max(temp, (int)(A[i + n - 1].real() / n1 + 0.5)); ans -= temp * 2; temp = z * z * n + y * z * 2; z += 1; temp = min(temp, z * z * n + y * z * 2); z -= 2; temp = min(temp, z * z * n + y * z * 2); // 有理有據的精度優化 ans += temp; printf("%d\n", ans); return 0; }

bzoj 4827: [HNOI2017]禮物 (FFT)