洛谷P3723 禮物

之前看到過,可是搞不倒。知道了算法以後就好搞了。算法

題意:給定兩個長爲n的序列,你能夠把某個序列所有加上某個數c,變成循環同構序列。ide

求你操做後的min∑(ai - bi函數

解:spa

設加上的數爲c,那麼獲得一個柿子:∑(ai - bi + c)²code

拆開:∑ai2 + ∑bi2 - 2∑aibi + nc² + 2c∑(ai - bi)blog

發現其中前兩項是常數不用管。第三項是卷積,後兩項是關於c的二次函數。it

因而後兩項用二次函數的對稱軸直接搞出來。第三項構造函數卷積,看哪一個位置的值最大便可。io

具體來講,把a複製成兩倍,反轉b。而後卷積出來的第n ~ 2n項就是。event

  1 #include <cstdio>
  2 #include <algorithm>
  3 #include <cmath>
  4 
  5 typedef long long LL;
  6 const int N = 300010;
  7 const double pi = 3.1415926535897932384626;
  8 const LL INF = 0x3f3f3f3f3f3f3f3f;
  9 
 10 struct cp {
 11     double x, y;
 12     cp(double X = 0, double Y = 0) {
 13         x = X;
 14         y = Y;
 15     }
 16     inline cp operator +(const cp &w) const {
 17         return cp(x + w.x, y + w.y);
 18     }
 19     inline cp operator -(const cp &w) const {
 20         return cp(x - w.x, y - w.y);
 21     }
 22     inline cp operator *(const cp &w) const {
 23         return cp(x * w.x - y * w.y, x * w.y + y * w.x);
 24     }
 25 }a[N], b[N];
 26 
 27 int r[N];
 28 LL A[N], B[N];
 29 
 30 inline void FFT(int n, cp *a, int f) {
 31     for(int i = 0; i < n; i++) {
 32         if(i < r[i]) {
 33             std::swap(a[i], a[r[i]]);
 34         }
 35     }
 36     for(int len = 1; len < n; len <<= 1) {
 37         cp Wn(cos(pi / len), f * sin(pi / len));
 38         for(int i = 0; i < n; i += (len << 1)) {
 39             cp w(1, 0);
 40             for(int j = 0; j < len; j++) {
 41                 cp t = a[i + len + j] * w;
 42                 a[i + len + j] = a[i + j] - t;
 43                 a[i + j] = a[i + j] + t;
 44                 w = w * Wn;
 45             }
 46         }
 47     }
 48     if(f == -1) {
 49         for(int i = 0; i <= n; i++) {
 50             a[i].x /= n;
 51         }
 52     }
 53     return;
 54 }
 55 
 56 int main() {
 57     int n, m;
 58     LL XX = 0, YY = 0, SX = 0, SY = 0;
 59     scanf("%d%d", &n, &m);
 60     n--;
 61     for(int i = 0; i <= n; i++) {
 62         scanf("%lld", &A[i]);
 63         SX += A[i];
 64         XX += A[i] * A[i];
 65         a[i].x = a[i + n + 1].x = A[i];
 66     }
 67     for(int i = 0; i <= n; i++) {
 68         scanf("%lld", &B[i]);
 69         SY += B[i];
 70         YY += B[i] * B[i];
 71         b[n - i].x = B[i];
 72     }
 73     int len = 2, lm = 1;
 74     while(len <= n * 3) {
 75         len <<= 1;
 76         lm++;
 77     }
 78     for(int i = 1; i <= len; i++) {
 79         r[i] = (r[i >> 1] >> 1) | ((i & 1) << (lm - 1));
 80     }
 81 
 82     FFT(len, a, 1);
 83     FFT(len, b, 1);
 84     for(int i = 0; i <= len; i++) {
 85         a[i] = a[i] * b[i];
 86     }
 87     FFT(len, a, -1);
 88 
 89     LL ans = -INF;
 90     for(int i = n; i <= n * 2; i++) {
 91         ans = std::max(ans, (LL)(a[i].x + 0.5));
 92     }
 93 
 94     double C = -1.0 * (SX - SY) / (n + 1);
 95     LL c = (int)(C);
 96     LL temp = std::min((n + 1) * c * c + 2 * (SX - SY) * c, (n + 1) * (c + 1) * (c + 1) + 2 * (SX - SY) * (c + 1));
 97     temp = std::min(temp, (n + 1) * (c - 1) * (c - 1) + 2 * (SX - SY) * (c - 1));
 98 
 99     printf("%lld\n", XX + YY - 2 * ans + temp);
100 
101     return 0;
102 }
AC代碼
相關文章
相關標籤/搜索