Codeforces Round 889 (Div. 2) C1 - C2

Problem - C1 - Codeforces

Problem - C2 - Codeforces

题意:

​ 有n个数字,可以选择任意两个位置i,j进行操作,使得ai=ai+aj(也即是aj加到ai),输出任意操作方案使得数组最后是不降的。esay-version要求在50次操作内完成,hard-version要求在31次操作内完成。

hard-version和easy-version有共同之处,所以放在一起讲了。

思路:

​ 首先,我们可以大致分成三种情况讨论:全为正数全为负数,以及有正有负(在这里0不会对最终答案产生影响,可以放进任意一种情况里)

​ 比较容易看出,对于全正的,我们只需要从左到右ai加到ai+1上,最后就一定能保证不降(每个数都等于它前一个数+kk大于等于0,则每个数都大于等于其前一个数)

​ 相对应的,对于全负的情况,我们只需要从右到左ai加到ai1上,也可以保证不降。

​ 可以容易看出,上面两种处理最多只需要操作19次,同时满足了两个版本的要求。

​ 那么接着考虑有正有负。

​ 对于easy-version,可以对数组中正数和负数的个数进行统计,同时记录正数中的最大值和负数中的最小值,如果正数个数大于负数个数,那么我们只需要让正数的最大值进行自加,直到大于负数最小值的绝对值,然后再把它加到所有负数上,就可以让所有负数变成正数,然后继续上面全正的操作即可。如果负数个数大于正数个数则同理。

​ 上面方案中最坏的情况就是1,1,1,1,1,1,1,1,1,1,1,20,20,20,20,20,20,20,20,20,在这种情况下,1也只需自加5次就已经大于20,加到每一个20需要操作9次,进行全加操作19次,最终操作次数也只是5+9+19=33,远远小于easy-version的操作上限,但却正好超过了hard-version的操作上限。

​ 思考更好的方法,观察可以发现,对于上面的情况,如果我们直接把20加到1上,使数组变成全负,那么总共只需要11+19=30次操作,就可以达成要求,对于hard-version的上限31,最多可以将大数加到别的数上12次(若数组大小为20),则总结一下,如果正数最大值大于等于负数最小值的绝对值,且负数个数小于等于12,那么我们执行直接变成全正相加会是更优的,若负数最小值的绝对值大于等于正数最大值则同理。如果都不满足,再使用一开始的思路(自增)就可以了。

​ 事实上上面的极限个数还会随着数组大小变化,但这个方法只会更优,且一定满足条件,所以不用继续优化也可以。

void QAQ(){
    int n;
    cin >> n;
    int minn = INF, maxx = -INF;
    vector<int> num(n + 1);
    for(int i = 1; i <= n; i ++){
        cin >> num[i];
        maxx = max(maxx, num[i]);
        minn = min(minn, num[i]);
    }
    queue<pii> op;
    if(minn >= 0){//全正
        for(int i = 1; i < n; i ++){
            // cout << i + 1 << " " << i << endl;
            op.push({i + 1, i});
        }
    }
    else if(maxx <= 0){//全负
        for(int i = n; i > 1; i --){
            // cout << i - 1 << " " << i << endl;
            op.push({i - 1, i});
        }
    }
    else{//有正有负另外统计
        int a = 0, b = 0, aa = 0, bb = 0;
        int acnt = 0, bcnt = 0;
        for(int i = 1; i <= n; i ++){
            if(num[i] > 0){
                if(num[i] > a){
                    aa = i, a = num[i];
                }
                acnt ++;
            }
            else if(num[i] < 0){
                if(num[i] < b){
                    bb = i, b = num[i];
                }
                bcnt ++;
            }
        }
        //如果是easy-version直接看最后的else也可以
        if(abs(a) > abs(b) && bcnt <= 12){
            for(int i = 1; i <= n; i ++){
                if(num[i] < 0){
                    op.push({i, aa});
                }
            }
            for(int i = 1; i < n; i ++){
                op.push({i + 1, i});
            }
        }
        else if(abs(b) > abs(a) && acnt <= 12){
            for(int i = 1; i <= n; i ++){
                if(num[i] > 0){
                    op.push({i, bb});
                }
            }
            for(int i = n; i > 1; i --){
                // cout << i - 1 << " " << i << endl;
                op.push({i - 1, i});
            }
        }
        else{
            if(acnt > bcnt){
                //正数多
                while(abs(a) < abs(b)){
                    a += a;
                    op.push({aa, aa});
                }
                for(int i = 1; i <= n; i ++){
                    if(num[i] < 0){
                        op.push({i, aa});
                    }
                }
                for(int i = 1; i < n; i ++){
                    op.push({i + 1, i});
                }
            }
            else{
                while(abs(b) < abs(a)){
                    b += b;
                    op.push({bb, bb});
                }
                for(int i = 1; i <= n; i ++){
                    if(num[i] > 0){
                        op.push({i, bb});
                    }
                }
                for(int i = n; i > 1; i --){
                    // cout << i - 1 << " " << i << endl;
                    op.push({i - 1, i});
                }
            }
        }
    }
    cout << op.size() << endl;
    while(!op.empty()){
        int x, y;
        tie(x, y) = op.front();
        op.pop();
        cout << x << " " << y << endl;
    }
}
posted @   一棵木头罢辽  阅读(30)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示