P3723 [AH2017/HNOI2017]礼物(FFT)
P3723 [AH2017/HNOI2017]礼物(FFT)
[AH2017/HNOI2017]礼物
题目描述
我的室友最近喜欢上了一个可爱的小女生。马上就要到她的生日了,他决定买一对情侣手环,一个留给自己,一个送给她。每个手环上各有
但是在她生日的前一天,我的室友突然发现他好像拿错了一个手环,而且已经没时间去更换它了!他只能使用一种特殊的方法,将其中一个手环中所有装饰物的亮度增加一个相同的非负整数
在将两个手环旋转且装饰物对齐了之后,从对齐的某个位置开始逆时针方向对装饰物编号
麻烦你帮他计算一下,进行调整(亮度改造和旋转),使得两个手环之间的差异值最小,这个最小值是多少呢?
输入格式
输入数据的第一行有两个数
接下来两行,每行各有
输出格式
输出一个数,表示两个手环能产生的最小差异值。注意在将手环改造之后,装饰物的亮度可以大于
样例 #1
样例输入 #1
5 6
1 2 3 4 5
6 3 3 4 5
样例输出 #1
1
提示
【样例解释】
需要将第一个手环的亮度增加
旋转一下第二个手环。对于该样例,是将第二个手环的亮度
此时两个手环的亮度差异值为
【数据范围】
对于
对于
对于
思路
这是一个
题意
给定两个数组
, 可以循环移动,选择整数 , 求 的最小值 。
分析
我们可以化简一下式子:
显然前两项是定值。
后面的两项是关于
所以问题就转换成了求最大的
先破环为链,即
考虑把
翻转
发现变成了一个卷积
就可以用
#include <bits/stdc++.h>
#define fu(x, y, z) for (int x = y; x <= z; x++)
#define fd(x, y, z) for (int x = y; x >= z; x--)
#define LL long long
using namespace std;
const int N = (1 << 18);
const double pi = acos(-1.0);
struct node {
double x, y;
} A[N], B[N];
int n, m, a[N], b[N], n1, m1, n2;
node operator + (node a, node b) { return (node){a.x + b.x , a.y + b.y};}
node operator - (node a, node b) { return (node){a.x - b.x , a.y - b.y};}
node operator * (node a, node b) { return (node){a.x * b.x - a.y * b.y , a.x * b.y + a.y * b.x};}
LL rev[N], sum[N], ans1, ans, t;
int read() {
int val = 0, fu = 1;
char ch = getchar();
while (ch < '0' || ch > '9') {
if (ch == '-')
fu = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
val = val * 10 + (ch - '0');
ch = getchar();
}
return val * fu;
}
void fft(int len, node *a, int inv) {
if (len == 1)
return;
node a1[(len >> 1) + 5], a2[(len >> 1) + 5];
for (int i = 0; i <= len; i += 2) {
a1[i >> 1] = a[i], a2[i >> 1] = a[i + 1];
}
fft(len >> 1, a1, inv);
fft(len >> 1, a2, inv);
node wn = (node){ cos(2.0 * pi / len), inv * sin(2.0 * pi / len) }, w = (node){ 1, 0 };
for (int i = 0; i < (len >> 1); i++, w = w * wn) {
a[i] = a1[i] + w * a2[i];
a[i + (len >> 1)] = a1[i] - w * a2[i];
}
}
void solve() {
fu(i, 0, n1) A[i].x = a[i + 1];
fu(i, 0, m1) B[i].x = b[i + 1];
int len = 1;
while (len <= n1 + m1) len <<= 1;
fft(len, A, 1), fft(len, B, 1);
fu(i, 0, len) A[i] = A[i] * B[i];
fft(len, A, -1);
fu(i, 0, m1 + n1 + 1) rev[i] = (LL)(A[i].x / len + 0.5);
}
int main() {
n = read(), m = read();
n1 = n - 1, n2 = (n << 1);
m1 = n2 - 1;
fu(i, 1, n) a[i] = read();
fu(i, 1, n) b[i] = read();
fu(i, 1, n) {
t += b[i] - a[i];
ans += a[i] * a[i] + b[i] * b[i];
b[i + n] = b[i];
}
int c1 = floor(t * 1.0 / n), c2 = ceil(t * 1.0 / n);
ans += min(n * c1 * c1 - 2 * c1 * t, n * c2 * c2 - 2 * c2 * t);
reverse(a + 1, a + n + 1);
solve();
fu (i , 0 , n) ans1 = max (ans1 , rev[i + n]);
ans -= ans1 * 2;
printf("%lld", ans);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 周边上新:园子的第一款马克杯温暖上架
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
· 使用C#创建一个MCP客户端