C. Make it Increasing

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 biai
注: 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} b610 都需要使用至少 1 次步数来平衡,如果其中 a 6 − 10 a_{6-10} a610某一个小于 a 5 a_5 a5则需要两步或更多等 ,而换来的只是 b 4 b_4 b4 不用动,而 b 1 − 3 b_{1-3} b13 仍需正常的偏移构造递增序列,实际上非常亏

在这里插入图片描述
综上,我们只需要枚举 1 − n 1 - n 1n 作为特殊点,然后计算对应的步数去最小即可

AC代码

#include <bits/stdc++.h>
#define endl '\n'
#define AC return 0;
using namespace std;
//#define ll long long
#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;
        // cout << pos << endl;
        //left
        for(int i = pos - 1; i >= 1; i--)
        {
            int c = b[i + 1] - b[i];
            int k = (c + e[i]) / e[i];
            // cout << k << endl;
            b[i] = k * e[i];
            res += k;
        }

        //rig
        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;
        }
        // for(int i = 1; i <= n; i++)
        //     cout << b[i] << " " ;
        // cout << endl;
        ans = min(ans,res);
    }    
    cout << ans << endl;
    
    
}

signed main()
{
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    //int T;cin >> T; while(T--)
    slove();
    AC
}

发现我的题解都好多画图(

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值