CF622D 排列数
1 CF622D 排列数
2 题目描述
时间限制 \(1s\) | 空间限制 \(256M\)
数组 \(a\) 包含两次从 \(1\) 到 \(n\) 的所有整数。你可以任意排列 \(a\) 中的任何数字。
\(x_i,y_i(x_i < y_i)\) 表示数字 \(i\) 在 \(a\) 中的位置。定义 \(d_i = y_i-x_i\) 为数字 \(i\) 之间的距离。排列数组 \(a\) 中的数字使得下面式子的和最小:
\(s = \sum_{i=1}^n\limits (n-i) * |d_i + i - n|\) 。
数据范围:\(1 ≤ n ≤ 5*10^5\)
3 题解
\(\sum_{i=1}^n\limits (n-i) * |d_i + i - n|\) 这个式子在所有的 \(d_i\) 都等于 \(n - i\) 时等于 \(0\)。那么我们如何构造出来一个满足所有 $d_i $ 都等于 \(n-i\) 的数列呢?我们发现:如果在 \(l, r\) 两个数中间插入 \(l+1, r-1\),这两个数之间隔的距离是 \(l, r\) 之间距离 \(+2\)。 也就是说,在 \(l+1, r-1\) 这个位置放的数必须是在 \(l, r\) 这个位置放的数 \(+2\)。也就是说,我们只需要如下构造,就可以求出正确的答案:
先放两个 \(1\),相隔 \(n-i-1\)。然后向中间慢慢加数,放的数从两个 \(3\) 一直到两个 \(n-1\)(\(n\) 为偶数)或者一个 \(n\)(\(n\) 为奇数)。随后两个是 \(2\),然后类似地往中间放数。最后一位是 \(n\)。
4 代码(空格警告):
#include <iostream>
using namespace std;
int n, cnt;
bool flag, flag2;
int main()
{
cin >> n;
cnt = 1;
while (1)
{
cout << cnt << " ";
if (cnt == 1 && flag) break;
if (n == 1) break;
if (n == 2)
{
cout << cnt << " ";
break;
}
else if (cnt == n)
{
flag = 1;
cnt -= 2;
}
else if (cnt == n-1)
{
flag = 1;
cout << cnt << " ";
cnt -= 2;
}
else if (cnt < n && !flag) cnt += 2;
else cnt -= 2;
}
cnt = 2;
flag = 0;
while (n >= 2)
{
cout << cnt << " ";
if (cnt == 2 && flag) break;
if (n == 2) break;
if (n == 3)
{
cout << cnt << " ";
break;
}
else if (cnt == n)
{
flag = 1;
cnt -= 2;
}
else if (cnt == n-1)
{
flag = 1;
cout << cnt << " ";
cnt -= 2;
}
else if (cnt < n && !flag) cnt += 2;
else cnt -= 2;
}
cout << n;
return 0;
}