cf*3 总结与反思

cf*3 总结与反思

C. Parity Shuffle Sorting

题意:
定义操作: 数组元素al 和 ar 。如果al + ar 为偶数,,al := ar, 否则 ar := al。
给一个数组,进行以上操作,最后得到操作多少次,将数组转换为非递减数组,并给出转换次数和每一次的操作。

解题思路: 将整个数组都转换为元素相同的数组的操作次数是小于n。可以考虑将整个数组赋值为一个相同的元素。因为操作比较特殊,是可以将第一个元素和最后一个元素操作为相同的元素。经过这一操作后,中间元素都可以经过操作转换为相同元素。

void solve() {
    int n; cin>>n;
    vector<int> a;
    for(int ip,i = 0; i < n; ++i) {
        cin>>ip; a.push_back(ip);
    }

    if(n == 1) { // 数组大小等于1时,自然是非递减的喽
        cout<<"0\n";
        return ;
    }

    vector<PII> vp; // 操作步骤
    
    if(a[0] != a[a.size()-1]) { // a[0] a[[n-1]不相等
        vp.push_back({1, a.size()});
        (a[0] + a[a.size()-1])%2 == 0 ? a[0] = a[a.size()-1] : a[a.size()-1] = a[0]; // 根据奇偶进行不同操作
    }
    for(int i = 1; i < a.size()-1; ++i) { // 对中间元素进行操作
        if((a[i] + a[a.size()-1])%2 == 0) { // 偶数 : 给al赋值
            a[i] = a[a.size()-1];
            vp.push_back({i+1, a.size()});
        } else { // 奇数:给ar赋值
            a[i] = a[0];
            vp.push_back({1, i+1});
        }
    }

    cout<<vp.size()<<endl;
    for(auto it: vp) cout<<it.first<<" "<<it.second<<endl;

}

C. Minimum Notation

题意:
操作:选中一个元素ch,将其删除。之后在任何位置插入 min ( ch + 1, 9)元素。
给定一串数字。进行该操作,得到字典序最小序列。

解题思路: 对序列中元素来说,删除哪一个元素,之后加入的元素的位置顺序都是对后面有关系的,但是同时又因为插入位置是任意的,动态规划思路难以想到解法。每一个插入的元素对后面都是有关系的,就表明可以经过排序得到最后元素,这是因为当插入最小的元素后,后面在插入都是在该元素后面插入的,保证了前面对于后面来说是一个最小字典序。又因为每次插入的元素都是大于等于原始元素,可以考虑用逆序对来解决问题。单调栈 + 逆序对。

void solve() {
    string str;
    cin>>str;
    int len = str.size();
    stack<int> sk;
    for(int i = 0; i < len; ++i) {
        // 前面元素大于该元素时
        while(sk.size() && str[sk.top()] > str[i]) {
            // 找到该元素最小的插入元素
            str[sk.top()] = min( char(str[sk.top()] + 1), '9');
            sk.pop();
        }// 输入下标
        sk.push(i);
    }
    // 排序
    sort(str.begin(), str.end());
    cout<<str<<endl;
}

C. Digital Logarithm

题意:
定义函数f:f为元素的十进制位数。
给定两个数组 a 和 b ,可以给ai或bj赋值f(ai)或f(bj),求最少多少次两个数组排序后相同。

解题思路: 首先考虑将两个数组的每个元素10进制位数用map进行叠加存储,之后从大到小进行赋值 f 的操作,但是发现这个并不满足要求(e.g. [334], [111] )。之后发现了一个更简单的方法,用优先队列(大顶堆)存储两个数组,遍历,对不相同的元素进行操作。

void solve() {
    priority_queue<int> pa, pb;
    int ip;
    int n; cin>>n;
    rep(i,1,n) {
        cin>>ip; pa.push(ip);
    }
    rep(i,1,n) {
        cin>>ip; pb.push(ip);
    }

    int cnt = 0;
    while(pa.size() && pb.size()) {
        int a = pa.top(), b = pb.top();

        if(a == b) {
            pa.pop(); pb.pop();
            continue;
        } else if(a > b) {
            pa.pop();
            pa.push(to_string(a).size());
        } else {
            pb.pop();
            pb.push(to_string(b).size());
        }
        cnt++;
    }
    cout<<cnt<<endl;

}

今日总结:

做到了一个关于单调栈和优先队列的题。
把之前stl中优先队列的操作都忘了

priority_queue<int> pa; // 大顶堆 top is bigger
priority_queue<int, vector<int>, greater<int> > pp; // 小顶堆

同时通过看题解,发现了一个判断10进制数的位数的更快函数,就是把数字转换为字符串,用字符串的判断长度的函数。

int ab = 3434;
cout<<to_string(ab).size();

同时因为这几周都有考试等其他琐碎的事情,cf做题好久没有做了。感觉有点生疏,对思维题的敏感度下降了。要多练练,多理解多敲敲模板!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

golemon.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值