4827: [Hnoi2017]礼物
Time Limit: 60 Sec Memory Limit: 512 MB
Submit: 267 Solved: 196
[Submit][Status][Discuss]
Description
我的室友最近喜欢上了一个可爱的小女生。马上就要到她的生日了,他决定买一对情侣手 环,一个留给自己,一
个送给她。每个手环上各有 n 个装饰物,并且每个装饰物都有一定的亮度。但是在她生日的前一天,我的室友突
然发现他好像拿错了一个手环,而且已经没时间去更换它了!他只能使用一种特殊的方法,将其中一个手环中所有
装饰物的亮度增加一个相同的自然数 c(即非负整数)。并且由于这个手环是一个圆,可以以任意的角度旋转它,
但是由于上面 装饰物的方向是固定的,所以手环不能翻转。需要在经过亮度改造和旋转之后,使得两个手环的差
异值最小。在将两个手环旋转且装饰物对齐了之后,从对齐的某个位置开始逆时针方向对装饰物编号 1,2,…,n,
其中 n 为每个手环的装饰物个数,第 1 个手环的 i 号位置装饰物亮度为 xi,第 2 个手 环的 i 号位置装饰物
亮度为 yi,两个手环之间的差异值为(参见输入输出样例和样例解释): \sum_{i=1}^{n}(x_i-y_i)^2麻烦你帮他
计算一下,进行调整(亮度改造和旋转),使得两个手环之间的差异值最小, 这个最小值是多少呢?
Input
输入数据的第一行有两个数n, m,代表每条手环的装饰物的数量为n,每个装饰物的初始 亮度小于等于m。
接下来两行,每行各有n个数,分别代表第一条手环和第二条手环上从某个位置开始逆时 针方向上各装饰物的亮度。
1≤n≤50000, 1≤m≤100, 1≤ai≤m
Output
输出一个数,表示两个手环能产生的最小差异值。
注意在将手环改造之后,装饰物的亮度 可以大于 m。
Sample Input
5 6
1 2 3 4 5
6 3 3 4 5
Sample Output
1
【样例解释】
需要将第一个手环的亮度增加1,第一个手环的亮度变为: 2 3 4 5 6 旋转一下第二个手环。对于该样例,是将第
二个手环的亮度6 3 3 4 5向左循环移动 2017-04-15 第 6 页,共 6 页 一个位置,使得第二手环的最终的亮度为
:3 3 4 5 6。 此时两个手环的亮度差异值为1。
HINT
对一个手环的修改等价于再另一个手环上修改相反数
那么可以假设修改一定发生在第一个手环上
假设第一个手环增加了 d 大力拆开答案的公式
∑ni=1(xi+d−yi)2=∑ni=1[x2i+y2i+d2+2d(xi−yi)−2xiyi]
前两项为定值
三四项可以通过枚举 d <script type="math/tex" id="MathJax-Element-3971">d</script>贪心选择最优的
最后一项,将两个手链进行一次NTT,对应系数加一下就行了
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<vector>
#include<queue>
#include<set>
#include<map>
#include<stack>
#include<bitset>
#include<ext/pb_ds/priority_queue.hpp>
using namespace std;
const int maxn = (1 << 17) + 233;
typedef long long LL;
const LL mo = 1004535809;
int n,m,N,Ans,w[maxn],_w[maxn],A[maxn],B[maxn],C[maxn];
inline int Mul(const LL &x,const LL &y) {return x * y % mo;}
inline int Add(const int &x,const int &y) {return x + y < mo ? x + y : x + y - mo;}
inline int Dec(const int &x,const int &y) {return x - y >= 0 ? x - y : x - y + mo;}
int ksm(int x,int y)
{
int ret = 1;
for (; y; y >>= 1)
{
if (y & 1) ret = Mul(ret,x);
x = Mul(x,x);
}
return ret;
}
void Rader(int *F)
{
int j = (N >> 1);
for (int i = 1; i < N - 1; i++)
{
if (i < j) swap(F[i],F[j]); int k = (N >> 1);
while (j >= k) j -= k,k >>= 1; j += k;
}
}
void NTT(int *F,int *w,int on)
{
Rader(F);
for (int k = 2; k <= N; k <<= 1)
for (int i = 0; i < N; i += k)
{
int now = 0;
for (int j = i; j < i + (k >> 1); j++)
{
int u = F[j],v = Mul(F[j + (k >> 1)],w[now]);
F[j] = Add(u,v); F[j + (k >> 1)] = Dec(u,v); now += N / k;
}
}
if (on == 1) return;
int Inv = ksm(N,mo - 2);
for (int i = 0; i < N; i++)
F[i] = Mul(F[i],Inv);
}
inline int getint()
{
char ch = getchar(); int ret = 0;
while (ch < '0' || '9' < ch) ch = getchar();
while ('0' <= ch && ch <= '9')
ret = ret * 10 + ch - '0',ch = getchar();
return ret;
}
int main()
{
#ifdef DMC
freopen("DMC.txt","r",stdin);
#endif
LL Min = 1E12,tot = 0,Max = 0;
n = getint(); m = getint(); N = 1;
for (int i = 0; i < n; i++)
A[i] = getint(),Ans += A[i] * A[i],tot += A[i];
for (int i = 0; i < n; i++)
B[i] = getint(),Ans += B[i] * B[i],tot -= B[i];
for (int c = -200; c <= 200; c++)
Min = min(Min,1LL * n * c * c + 2LL * c * tot);
while (N <= n) N <<= 1; N <<= 1;
w[0] = 1; w[1] = ksm(3,(mo - 1) / N);
for (int i = 2; i <= N; i++) w[i] = Mul(w[i - 1],w[1]);
for (int i = 0; i <= N; i++) _w[i] = w[N - i];
reverse(B,B + n); NTT(A,w,1); NTT(B,w,1);
for (int i = 0; i < N; i++) C[i] = Mul(A[i],B[i]);
NTT(C,_w,-1); int tmp = 2 * n - 1;
for (int i = n - 1; i >= 0; i--)
Max = max(Max,1LL * C[i] + C[tmp--]);
cout << Ans - 2LL * Max + Min << endl;
return 0;
}