https://codeforces.com/contest/1668/problem/C input
5
1 2 3 4 5
output
4
input
7
1 2 1 2 1 2 1
output
10
input
8
1 8 2 7 3 6 4 5
output
16
题意
给定
n
n
n 以及 n 个数表示为
a
i
a_i
ai? ,现你需要通过最小操作数将
b
b
b 数组变成严格递增的数组,其中
b
b
b 数组内元素一开始都是 0 ,每次操作中,对于
b
i
b_i
bi? 可以 变成
b
i
+
a
i
b_i + a_i
bi?+ai?
o
r
or
or
b
i
?
a
i
b_i - a_i
bi??ai? 注:
n
n
n 为
5
e
3
5e3
5e3
思路 对于一开始都相等的序列,选定某个特殊点,则其左边都减小,右边都增大
我们可以想一下,最终构造的方法是不是特殊点一定是是
0
0
0 ,即不用动 (如下图)(并不严格的证明) 假设一下
b
5
b_5
b5? 先
+
a
5
+a_5
+a5? 对于
b
6
?
10
b_{6-10}
b6?10? 都需要使用至少 1 次步数来平衡,如果其中
a
6
?
10
a_{6-10}
a6?10?某一个小于
a
5
a_5
a5?则需要两步或更多等 ,而换来的只是
b
4
b_4
b4? 不用动,而
b
1
?
3
b_{1-3}
b1?3? 仍需正常的偏移构造递增序列,实际上非常亏
综上,我们只需要枚举
1
?
n
1 - n
1?n 作为特殊点,然后计算对应的步数去最小即可
AC代码
#include <bits/stdc++.h>
#define endl '\n'
#define AC return 0;
using namespace std;
#define int long long
int e[5005];
int b[5005];
void slove()
{
int n;
cin >> n;
for(int i = 1; i <= n; i++)
cin >> e[i];
int ans = 1e18;
for(int pos = 1; pos <= n; pos++)
{
int res = 0;
for(int i = 1; i <= n; i++)
b[i] = 0;
for(int i = pos - 1; i >= 1; i--)
{
int c = b[i + 1] - b[i];
int k = (c + e[i]) / e[i];
b[i] = k * e[i];
res += k;
}
for(int i = pos + 1; i <= n; i++)
{
int c = b[i - 1] - b[i];
int k = (c + e[i]) / e[i];
b[i] = k * e[i];
res += k;
}
ans = min(ans,res);
}
cout << ans << endl;
}
signed main()
{
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
slove();
AC
}
发现我的题解都好多画图(
|