cf*反思与总结

本文介绍了两个编程题目,分别是关于矩阵中L型块的清零操作和数组元素通过特定运算达到一致性的题目。对于矩阵问题,重点在于找出不同数量1的L型块所能进行的操作次数;对于数组问题,关键在于理解元素模10运算后的规律。通过二分查找和模拟操作,可以得出解决方案。这两个问题都涉及到了寻找规律和高效算法的应用。
摘要由CSDN通过智能技术生成

C. Corners

题意:
题目给定一个n行m列且仅有1和0组成的矩阵,每次操作选择一个2*2的L型块,要求这个L块至少有1个1,然后将这个L块全部清0。求最多能操作多少次。

解题思路: 找规律和模拟。发现2*2正方形有4,3,2,1个1的个数时,可以进行相应的转换。

void solve() {
    int n,m; cin>>n>>m;

    rep(i,0,n-1) {
        cin>>gt[i];
    }
    int sum = 0;
    char ch;
    rep(i,0,n-1) {
        rep(j,0, m-1) {
            pt[i][j] = (gt[i][j]=='1' ? 1: 0);
            sum += pt[i][j];
        }
    }
    int mi = 0x3f3f3f3f;
    rep(i,0, n-2) {
        rep(j,0, m-2) {
            int s=  0;
            s = ( pt[i][j] + pt[i][j+1] + pt[i+1][j] + pt[i+1][j+1]);
            mi = min(s, mi);
        }
    }

    int ans  =0;
    if(mi == 4) ans = sum - 2;
    else if (mi == 3) ans = sum - 1;
    else ans = sum;
    cout<<ans<<endl;
}

E. Add Modulo 10

题意:
每个数组元素可以一直进行 ai + ai % 10。
问是否存在经过多次后,数组内元素值一样。

解题思路: 规律题。 首先可以想到mod10为0的元素不管怎么进行操作都是不变的,同时mod5可以经过一次操作,转换为0,进而与0一样。其他的都是可以转换为2,4,6,8,… 到最后以20为一个循环。数组mod10为0,5的转换为0后就停止,不能增加数字了,而其余的进行操作后,到2,4,6,8后表示后面都是一个20循环,可以到2,4,6,8停止,对其mod20。到最后,判断是否有不一样的数字。

void solve() {
    int n; cin>>n;
    vector<int> a(n);
    for(int i = 0; i < n; ++i) {
        cin>>a[i];
        while(a[i]%10 != 2 && a[i]%10 != 0) {
            a[i] += a[i] % 10;
        }
        if(a[i]%10 == 2) a[i] = a[i] % 20;
    }
    bool fg = 1;
    rep(i,1,n-1) {
        if(a[i] != a[i-1]) {
            fg = 0; break;
        }
    }
    if(fg) {
        puts("Yes");
    } else {
        puts("No");
    }
}

C. Mark and His Unfinished Essay

题意:
一个字符串 ,执行c个[l, r] 复制操作将其添加到末尾。q次询问,每次回答字符串该位置的字符ch

解题思路: 用pair或map将每一次复制append操作的前一个R的记录,并记录该次的复制开始l。查找用二分查找。

void solve() { // LL == long long
    LL n, c,q,l,r; cin>>n>>c>>q;
    string str; cin>>str;
    map<LL,LL> mp; // map
    LL ed = n; // 前一个的R,即前一个的字符串长度
    while(c--) {
        cin>>l>>r;
        mp[ed + 1] = l; // 映射 这次复制的开始下标l
        ed += r - l + 1; // +
    }

    while(q--) {
        cin>>l;
        /*
            为什么二分,因为存在 [1, 50] 长度 
                进行两次操作  [51,67]--> 30  [68 70]--> 2 这个
        */
        while(l > n) { // 得到大于查询l的第一个大于的地址并减到下一个地址
            LL t = (--mp.upper_bound(l))->first;
            LL dif = l - t; // 
            l = mp[t] + dif; // 得到下一个的L
        }
        cout<<str[l-1]<<endl;
    }
}

总结

规律题没找找思路,以一个死思路一路走到黑了。下次一定要注意,一二十分钟没有ac就换思路。
对map<int,int>的 upper_bound(key) 有了更深的影响和学习。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

golemon.

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

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

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

打赏作者

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

抵扣说明:

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

余额充值