题解 | #小红的乘2除2#

小红的乘2除2

https://ac.nowcoder.com/acm/contest/85187/D

答案只会有3种情况, 一.在同一个数上作除2,乘2。 二.在相邻的数作除2,乘2。 三.在不相邻的数上作除2,乘2。 第1,2 种情况可以在O(n)的时间复杂度内解决,只需要计算变化量。 第3种情况对每个数的乘2和除2的变化量分别存到vector p1, p2中并排序,对每p1的的变化量在p2中从小到大找第一个不相邻的位置来更新,p1的每个数最多会在p2中找3个位置,所以复杂度也是O(n)。 总的时间复杂度是O(nlogn)

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pi = pair<ll, ll>;
const int N = 1e6+ 10;
ll n,m;
ll a[N];
void solve()
{
    cin >> n;
    vector<pi> p1, p2;
    for(int i = 1; i <= n; i++) cin >> a[i];
    a[0] = a[1], a[n + 1] = a[n];
    ll all = 0;    
    for(int i = 1; i < n; i++) {
        all += abs(a[i] - a[i + 1]);
    }
    ll res = 1e18;
    for(int i = 1; i <= n; i++) {
    	//预处理每个位置*2的变化量
        ll tem = 0, pre = 0;
        if(i > 1) tem += abs(a[i-1] - a[i] * 2), pre += abs(a[i] - a[i - 1]);
        if(i < n) tem += abs(a[i+1] - a[i] * 2), pre += abs(a[i + 1] - a[i]);
        p1.push_back({tem - pre, i});
        //预处理每个位置/2的变化量
        tem = 0, pre = 0;
        if(i > 1) tem += abs(a[i-1] - a[i] / 2), pre += abs(a[i] - a[i - 1]);
        if(i < n) tem += abs(a[i+1] - a[i] / 2), pre += abs(a[i + 1] - a[i]);
        p2.push_back({tem - pre, i});
        //第一种情况,在同一个位置上 *2 后再 /2
        tem = 0;
        pre = abs(a[i - 1] - a[i]) + abs(a[i] - a[i + 1]);
        ll t = (a[i] / 2) * 2;
        if(i > 1) tem += abs(a[i - 1] - t);
        if(i < n) tem += abs(t - a[i + 1]);
        res = min(res, all - pre + tem);
        if(i < n) {
        	//第二种情况,在相邻个位置上 *2 后再 /2,前一个 *2 , 后一个 /2
            tem = 0, pre = (abs(a[i - 1] - a[i]) + abs(a[i] - a[i + 1]) + abs(a[i + 1] - a[i + 2]));
            ll t1 = a[i] * 2, t2 = a[i + 1] / 2;
            if(i > 1) tem += abs(a[i-1] - t1);
            tem += abs(t1 - t2);
            if(i + 1 < n)
                tem += abs(t2 - a[i + 2]);
            res = min(res, all - pre + tem);
            tem = 0;
            // 前一个 /2 , 后一个 *2
            t1 = a[i] / 2, t2 = a[i + 1] * 2;
            if(i > 1) tem += abs(a[i-1] - t1);
            tem += abs(t1 - t2);
            if(i + 1 < n)
                tem += abs(t2 - a[i + 2]);
            res = min(res, all - pre + tem);
        }
    }
    sort(p1.begin(), p1.end());
    sort(p2.begin(), p2.end());
    // 第三种情况
    for(auto i: p1) { // 看起来复杂度像是O(n^2),实际上第二层最多遍历3次。
        for(auto j: p2) {
            if(abs(i.second - j.second) > 1) {
                res = min(res, all + i.first + j.first);
                break;
            }
        }
    }
    cout << res;
}
int main()
{
  // 请在此输入您的代码
    ios::sync_with_stdio(0);
    cin.tie(0);
    int _ = 1;
//     cin >> _;
    while(_--) solve();
}
全部评论

相关推荐

我已成为0offer的糕手:别惯着,胆子都是练出来的,这里认怂了,那以后被裁应届被拖工资还敢抗争?
点赞 评论 收藏
分享
2 收藏 评论
分享
牛客网
牛客企业服务