题解 | #小红的乘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();
}
全部评论

相关推荐

ALEX_BLX:这华子能怪谁呢,池子泡这么深,每年几乎都是最晚一批开出来的公司,人才早就给抢走了。又不是人人都是博士生
点赞 评论 收藏
分享
05-11 11:48
河南大学 Java
程序员牛肉:我是26届的双非。目前有两段实习经历,大三上去的美团,现在来字节了,做的是国际电商的营销业务。希望我的经历对你有用。 1.好好做你的CSDN,最好是直接转微信公众号。因为这本质上是一个很好的展示自己技术热情的证据。我当时也是烂大街项目(网盘+鱼皮的一个项目)+零实习去面试美团,但是当时我的CSDN阅读量超百万,微信公众号阅读量40万。面试的时候面试官就告诉我说觉得我对技术挺有激情的。可以看看我主页的美团面试面经。 因此花点时间好好做这个知识分享,最好是单拉出来搞一个板块。各大公司都极其看中知识落地的能力。 可以看看我的简历对于博客的描述。这个帖子里面有:https://www.nowcoder.com/discuss/745348200596324352?sourceSSR=users 2.实习经历有一些东西删除了,目前看来你的产出其实很少。有些内容其实很扯淡,最好不要保留。有一些点你可能觉得很牛逼,但是面试官眼里是减分的。 你还能负责数据库表的设计?这个公司得垃圾成啥样子,才能让一个实习生介入数据库表的设计,不要写这种东西。 一个公司的财务审批系统应该是很稳定的吧?为什么你去了才有RBAC权限设计?那这个公司之前是怎么处理权限分离的?这些东西看着都有点扯淡了。 还有就是使用Redis实现轻量级的消息队列?那为什么这一块不使用专业的MQ呢?为什么要使用redis,这些一定要清楚, 就目前看来,其实你的这个实习技术还不错。不要太焦虑。就是有一些内容有点虚了。可以考虑从PR中再投一点产出
点赞 评论 收藏
分享
评论
2
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务