首页 > 其他分享 >Codeforces Round 889 (Div. 2) C1 - C2

Codeforces Round 889 (Div. 2) C1 - C2

时间:2023-07-30 16:27:38浏览次数:42  
标签:20 version int 889 Codeforces 负数 num 正数 Round

Problem - C1 - Codeforces

Problem - C2 - Codeforces

题意:

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

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

思路:

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

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

​ 相对应的,对于全负的情况,我们只需要从右到左把\(a_i\)加到\(a_{i - 1}\)上,也可以保证不降。

​ 可以容易看出,上面两种处理最多只需要操作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;
    }
}

标签:20,version,int,889,Codeforces,负数,num,正数,Round
From: https://www.cnblogs.com/woods4325/p/17591580.html

相关文章

  • Codeforces #889 div2 B
    B.LongestDivisorsInterval做法:假设我们找到了一个最大区间[l,r],这个区间的长度为k,那么这个区间里有一个数必定是k的倍数(自己举个例子就能知道了),因此n也是k的倍数。那么我们再缩小一下区间长度,变为k-1,这个区间可以是[l,r-1],也可以是[l+1,r],这其中必定有一个数是k-......
  • Codeforces Round 889 (Div. 2) 题解
    \(6\)题只做出来\(1\)题,损失惨重A.DaltontheTeacher显然,答案一定和最初的不满意人数有关,所以输入的时候统计一下然后,将不满意的人的座位每两个人交换一次即可,交换次数就是答案如果不满意人数是奇数,那么答案还要加\(1\)时间复杂度\(O(n)\)(输入的复杂度)B.LongestD......
  • Codeforces Round 889 (Div. 1) 题解
    A1.Dual(EasyVersion)https://codeforces.com/contest/1854/problem/A1题意给定一个长度为\(n\)的序列\(a_1,a_2,\dots,a_n\),你可以做以下操作:选定两个下标\(i,j(1\leqi,j\leqn)\),\(i,j\)可以相同,然后\(a_i\leftarrowa_{i}+a_j\)。要求构造一种操作......
  • Round 889 Div.2 意识流简记。
    太丢人了!D2D狂吃6发罚时,D2C都不会!不过无所谓,反正老年选手就是打着玩。D2A.答案为\(\lceil\frac{\sum_{i=1}^n[a_i=i]}{2}\rceil\)。D2B.我不会啊,猜了一下只需要枚举\(\le2000\)的,莫名其妙过了。D2C1/C2.不会。D2D.考虑动态维护前\(i\)个能凑出的数的集合,适时......
  • Codeforces Round 105 (Div. 2) - D. Bag of mice DP 或 记忆化搜索 求概率
    D.Bagofmice题意待补充~思路可利用DP或者记忆化搜索求解本问题,实际上这两个方法等价。当\(w=0\)时必输当$w\ne0$但$b=0$时必赢剩下的情况,先考虑一个问题:赢的局面是怎么构成的?代码记忆化搜索//>>>Qiansui#include<bits/stdc++.h>#definelllong......
  • Educational Codeforces Round 152 (Rated for Div. 2)
    传送阵T1MorningSandwich题目大意\(t\)个测试,每个测试给三个正整数\(b,c,h\),分别表示面包和两种馅料的个数,每两个面包之间必须放一个馅料,问最多能摆几层?思路我们发现\(c,h\)所表示的两种馅料其实相差不大,所以我们可以分两种情况\(a>c+h\)因为开头总是面包,所以要+......
  • Codeforces Round 888 (Div. 3)
    CodeforcesRound888(Div.3)T1​ 思路:直接模拟。T2​思路:首先记录原始数组的奇偶性,然后将奇数、偶数分为不同两组进行排序,然后再根据原数组的奇偶性按顺序填入奇数偶数,最后判断整个数组是否非递减。T3思路:我们已知开始在\(a_1\),最后在\(a_n\)。那么当\(a_1\ne......
  • Educational Codeforces Round 152 (Rated for Div. 2) 题解
    \(6\)题做出来\(3\)题,这一次的D题没能复刻上一次Round888Div.3最后几分钟AC的奇迹A.MorningSandwich大水题,5min时间4min都在翻译题面直接拿\(b\)和\(c+h\)进行比较分类讨论即可单次操作时间复杂度\(O(1)\)B.Monsters首先有一个特别显然、复杂度特别高的......
  • @Around简单使用示例——SpringAOP增强处理
    @Around简单使用示例——SpringAOP增强处理@Around的作用既可以在目标方法之前织入增强动作,也可以在执行目标方法之后织入增强动作;可以决定目标方法在什么时候执行,如何执行,甚至可以完全阻止目标目标方法的执行;可以改变执行目标方法的参数值,也可以改变执行目标方法之后的返回......
  • Educational Round 147
    前言:非常好场次编号,爱来自小粉兔。唉,GF。A.shaber模拟。B.shaber。找最大的满足\(a_{l\simr}\)和\(a'_{l\simr}\)有不同,且\(a'_{l\simr}\)递增的\(\langlel,r\rangle\)即可。\(\mathcalO(n)\)。C.shaber。枚举字符\(c\),非\(c\)最大连续段长是\(k\)的......