[AH2017/HNOI2017] 礼物(fft)
题目描述
我的室友最近喜欢上了一个可爱的小女生。马上就要到她的生日了,他决定买一对情侣手环,一个留给自己,一个送给她。每个手环上各有 \(n\) 个装饰物,并且每个装饰物都有一定的亮度。
但是在她生日的前一天,我的室友突然发现他好像拿错了一个手环,而且已经没时间去更换它了!他只能使用一种特殊的方法,将其中一个手环中所有装饰物的亮度增加一个相同的非负整数 \(c\)。并且由于这个手环是一个圆,可以以任意的角度旋转它,但是由于上面装饰物的方向是固定的,所以手环不能翻转。需要在经过亮度改造和旋转之后,使得两个手环的差异值最小。
在将两个手环旋转且装饰物对齐了之后,从对齐的某个位置开始逆时针方向对装饰物编号 \(1 \sim n\),其中 \(n\) 为每个手环的装饰物个数, 第 \(1\) 个手环的 \(i\) 号位置装饰物亮度为 \(x_i\),第 \(2\) 个手环的 \(i\) 号位置装饰物亮度为 \(y_i\),两个手环之间的差异值为(参见输入输出样例和样例解释):
\[\sum_{i=1}^{n} (x_i-y_i)^2 \]麻烦你帮他计算一下,进行调整(亮度改造和旋转),使得两个手环之间的差异值最小,这个最小值是多少呢?
数据范围
对于 \(30\%\) 的数据,\(n \le 500\),\(m \le 10\);
对于 \(70\%\) 的数据,\(n \le 5000\);
对于 \(100\%\) 的数据,\(1 \le n \le 50000\), \(1 \le a_i \le m \le 100\)。
解法
首先我们先列出来,其实就是求\(\sum_1^n[x_i^2+y_i^2+c^2+2*c(x_i-y_i)-x_i*y_i]\)
然后惊喜的发现,\(x_i^2\)与\(y_i^2\)是固定值,\(c^2+2*c(x_i-y_i)\)是一个二次函数,我们也能求出极值,而且注意他们的值是与序列顺序无关的。那么此时就剩下最后一项\(x_i*y_i\)了。我们只需要让这项最大即可。如果我们枚举对齐方式,然后再\(O(n)\)地计算其值,时间复杂度为\(O(n^2)\)。是显然我们无法接受的。
然后我们如果快速算呢,icpc澳门有一道题也用到了同样的处理,就是将其中一个数组倒置,然后进行卷积。假设我们从第0项构建多项式,那么第n-1项到第2n-1项的系数,即为我们\(On\)要求的值。此时因为用了fft,时间复杂度优化到\(O(nlogn)\)。即可通过此题。、
#include<bits/stdc++.h>
#define ll long long
#define i64 long long
using namespace std;
typedef complex<double> comp;
const int MAXN = 3000005;
comp A[MAXN], B[MAXN], ans[MAXN];
int rev[MAXN];
const comp I(0, 1);
const double PI = acos(-1);
void fft(comp F[], int N, int inv = 1)
{
int bit = log2(N);
for (int i = 0; i < N; ++i)
{
rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (bit - 1));
if (i < rev[i])
swap(F[i], F[rev[i]]);
}
for (int l = 1; l < N; l *= 2) // 枚举合并前的区间长度
{
comp step = exp(inv * PI / l * I);
for (int i = 0; i < N; i += l * 2) // 遍历起始点
{
comp cur(1, 0);
for (int k = i; k < i + l; ++k)
{
comp g = F[k], h = F[k + l] * cur;
F[k] = g + h, F[k + l] = g - h;
cur *= step;
}
}
}
if (inv == -1)
for (int i = 0; i < N; ++i)
F[i] /= N;
}
void solve(){
int n,m;cin>>n>>m;vector<int>a(n+1);vector<int>b(n+1);
ll sum=0ll,temp1=0;
for(int i=1;i<=n;i++){
cin>>a[i];sum+=a[i]*a[i];temp1+=a[i];
}
for(int i=1;i<=n;i++){
cin>>b[i];sum+=1ll*b[i]*b[i];temp1-=b[i];
}
int n1=-floor(1.0*temp1/n);
int n2=-ceil(1.0*temp1/n);;
sum+=(ll)min(n1*n1*n+2*n1*temp1,n2*n2*n+2*n2*temp1);
m=2*n-1;n--;
int N = 1 << int(log2(n + m) + 1);
for(int i=0;i<=m;i++)A[i]=a[n-(i%(n+1))+1];
for(int i=0;i<=n;i++)B[i]=b[i+1];
fft(A, N), fft(B, N);
for (int i = 0; i < N; ++i)ans[i] = A[i] * B[i];
fft(ans, N, -1);
int temp2=int(ans[n].real() + 0.1);
for (int i = n+1; i<=n+m; ++i){
temp2=max(temp2,int(ans[i].real() + 0.1));
}
cout<<max(sum-2ll*temp2,0ll)<<"\n";
}
signed main(){
std::ios::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);
srand((unsigned)time(NULL));
//int t;cin>>t;while(t--)
solve();
}
标签:le,int,sum,fft,手环,temp1,AH2017HNOI2017,装饰物,礼物
From: https://www.cnblogs.com/shi5/p/18048134