【數學】[AH2017/HNOI2017]禮物
阿新 • • 發佈:2021-06-16
先列舉 \(c\) 打一個表,然後發現這是個關於 \(c\) 的凸函式。
int main() { read(n); read(m); for (int i=1; i<=n; i++) read(A[i]); for (int i=1; i<=n; i++) read(B[i]); for (int j=-10; j<=10; j++) { for (int i=1; i<=n; i++) A[i]+=j; int mn=inf; for (int k=0; k<n; k++) { int cnt=0; for (int i=1; i<=n; i++) { int nxt=(i+k)%n; if (nxt==0) nxt=n; cnt+=(A[nxt]-B[i])*(A[nxt]-B[i]); } mn=min(mn, cnt); } printf("%d\n", mn); for (int i=1; i<=n; i++) A[i]-=j; } return 0; }
輸出的是:
628
521
424
337
260
193
136
89
52
25
8
1
4
17
40
73
116
169
232
305
388
於是考慮三分一個 \(c\),然後列舉那個移位,因為 \(c\in[-m,m]\) 所以也不需要三分。
考慮拆式子:\((a+c-b)^2=a^2+b^2+c^2+2ac-2bc-2ab\)。然後只有 \(2ab\) 不是定值,於是只用求 \(2ab\) 的最大值即可。然後我們發現是 \(\sum A_{i+k}\times B_{i}\),令 \(\bar{B_i}=B_{n-i+1}\),然後就是個卷積式,所以最後移 \(k\) 位的答案就是捲起來後 \([x^{n+k+1}]\)
#include <bits/stdc++.h> using namespace std; const double eps=1e-6; const double pi=acos(-1.0); const int MAXN=1000005; const int inf=1e9; template <typename T> void read(T &x) { T flag=1; char ch=getchar(); for (; '0'>ch||ch>'9'; ch=getchar()) if (ch=='-') flag=-1; for (x=0; '0'<=ch&&ch<='9'; ch=getchar()) x=x*10+ch-'0'; x*=flag; } struct com{ double x, y; com(){}; com(double _x, double _y) { x=_x, y=_y; } friend com operator + (com u, com v) { return com(u.x+v.x, u.y+v.y); } friend com operator - (com u, com v) { return com(u.x-v.x, u.y-v.y); } friend com operator * (com u, com v) { return com(u.x*v.x-u.y*v.y, u.x*v.y+u.y*v.x); } friend com operator * (com u, double v) { return com(u.x*v, u.y*v); } friend com operator / (com u, double v) { return com(u.x/v, u.y/v); } }; int n, m; int A[100005], B[100005]; int rev[MAXN]; com F[MAXN], G[MAXN]; void fft(com*f, int n, int op) { int len=(1<<n); for (int i=0; i<len; i++) if (i<rev[i]) swap(f[i], f[rev[i]]); for (int i=1; i<len; i<<=1) { com wn1=com(cos(1.0*pi/i), 1.0*op*sin(1.0*pi/i)); for (int j=0; j<len; j+=(i<<1)) { com wnk=com(1, 0); for (int k=0; k<i; k++) { com x=f[j+k], y=f[j+k+i]*wnk; f[j+k]=x+y; f[j+k+i]=x-y; wnk=wnk*wn1; } } } if (op==-1) for (int i=0; i<len; i++) f[i]=f[i]/(1.0*len); } void poly_mul(com *f, com *g, int n, int m) { int len=1, lg=0; while (len<=n+m) len<<=1, lg++; for (int i=0; i<MAXN; i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<(lg-1)); fft(f, lg, 1); fft(g, lg, 1); for (int i=0; i<len; i++) f[i]=f[i]*g[i]; fft(f, lg, -1); } int main() { int ans=0; read(n); read(m); int sum1=0, sum2=0; for (int i=1; i<=n; i++) read(A[i]), ans+=A[i]*A[i], sum1+=A[i]; for (int i=1; i<=n; i++) read(B[i]), ans+=B[i]*B[i], sum2+=B[i]; for (int i=1; i<=n; i++) A[i+n]=A[i]; for (int i=1; i<=(n<<1); i++) F[i].x=A[i]; for (int i=1; i<=(n<<1); i++) G[i].x=(i<=n?B[n-i+1]:0); poly_mul(F, G, n<<1, n<<1); int ANS=inf; int mx=-inf; for (int i=0; i<n; i++) mx=max(mx, (int)round(F[i+n+1].x)); for (int j=-m; j<=m; j++) { ANS=min(ANS, ans+j*j*n+2*sum1*j-2*sum2*j-2*mx); } printf("%d", ANS); return 0; }