牛客-模拟、枚举、贪心 2022.11.15

本文探讨了多种算法在处理字符串查找和区间问题中的应用,包括二分查找法解决子序列问题,处理手表时间的匹配,01串的遍历,以及区间密码的异或运算解密。同时,还介绍了如何通过优化处理确保奶牛的防晒需求。这些实例展示了算法在信息技术领域的实际应用和解决问题的高效性。
摘要由CSDN通过智能技术生成

月月查华华的手机

按照字母A-Z的顺序,分别按照下标的从小到大记录每个字母的位置。之后对于每个名字的查询,从名字的第一个字母出现的第一个位置开始,二分查找之后每个字母的位置是否大于当前的位置,如果大于,更新当前位置,直至名字数组结束,说明存在子序列,否则不存在。

对于第一个字母是否存在的情况在遍历之前进行特判。

#include <bits/stdc++.h>
using namespace std;
int main() {
    string A;
    cin >> A;
    vector<vector<int>> p;
    for(int i = 0; i < 26; i++) {
        vector<int> tmp;
        p.emplace_back(tmp);
    }
    for(int i = 0; i < A.size(); i++)
        p[A[i] - 'a'].emplace_back(i);
    int n;
    cin >> n;
    for(int i = 0; i < n; i++) {
        string B;
        cin >> B;
        if(p[B[0] - 'a'].size() == 0) {
            cout << "No\n";
            continue;
        }
        int start = p[B[0] - 'a'][0];
        bool flag = true;
        for(int j = 1; j < B.size(); j++) {
            int idx = upper_bound(p[B[j] - 'a'].begin(), p[B[j] - 'a'].end(), start) - p[B[j] - 'a'].begin();
            if(idx == p[B[j] - 'a'].size()) {
                flag = false;
                break;
            }
            start = p[B[j] - 'a'][idx];
        }
        if(flag)
            cout << "Yes\n";
        else
            cout << "No\n";
    }
    return 0;
}

ranko的手表

遍历所有的时间,记录所有符合的开始时间和结束时间,遍历符合条件的开始时间数组和符合条件的结束时间数组,两者时间不能相等,记录最大差值和最小差值即可。

#include <bits/stdc++.h>
using namespace std;
int main() {
    string s1, s2;
    cin >> s1 >> s2;
    vector<int> res1;
    for(int i = 0; i <= 1439; i++) {
        int tenhour = (i / 60) / 10, gehour = (i / 60) % 10;
        int tenmin = (i % 60) / 10, gemin = (i % 60) % 10;
        if(s1[0] != '?' && tenhour != (s1[0] - '0'))
            continue;
        if(s1[1] != '?' && gehour != (s1[1] - '0'))
            continue;
        if(s1[3] != '?' && tenmin != (s1[3] - '0'))
            continue;
        if(s1[4] != '?' && gemin != (s1[4] - '0'))
            continue;
        res1.emplace_back(i);
    }
    vector<int> res2;
    for(int i = 0; i <= 1439; i++) {
        int tenhour = (i / 60) / 10, gehour = (i / 60) % 10;
        int tenmin = (i % 60) / 10, gemin = (i % 60) % 10;
        if(s2[0] != '?' && tenhour != (s2[0] - '0'))
            continue;
        if(s2[1] != '?' && gehour != (s2[1] - '0'))
            continue;
        if(s2[3] != '?' && tenmin != (s2[3] - '0'))
            continue;
        if(s2[4] != '?' && gemin != (s2[4] - '0'))
            continue;
        res2.emplace_back(i);
    }
    int min1 = INT_MAX, max1 = INT_MIN;
    for(int i = 0; i < res1.size(); i++) {
        for(int j = 0; j < res2.size(); j++) {
            if(res1[i] >= res2[j])
                continue;
            min1 = min(min1, res2[j] - res1[i]);
            max1 = max(max1, res2[j] - res1[i]);
        }
    }
    cout << min1 << " " << max1 << endl;
    return 0;
}

牛妹和01串

模拟遍历01串即可。

#include <bits/stdc++.h>
using namespace std;
int main() {
    string s;
    cin >> s;
    int res = 0, start = 0;
    while(start < s.size()) {
        bool flag = false;
        for(int j = start + 1; j < s.size(); j++) {
            if(s[j] == s[start])
                continue;
            else {
                flag = true;
                start = j;
                break;
            }
        }
        if(flag) {
            res += 1;
            start += 1;
        } else
            break;
    }
    cout << res << endl;
    return 0;
}

兔子的区间密码

异或运算+大数据规模,考虑采用位运算,位运算需要记录64位二进制数。可以观察一下样例的几组数据的规律,如果区间最大值的二进制位数相较于最小值要高出一位以上,即最大值二进制最高位为一,而最小值的该位置为零,最小值在下一位才为一,这种情况是大一位;如果是最小值的该位置后几个位置才存在第一个一,说明更小。则说明存在两个数字,可以使得异或值为所有二进制位值都为一,只从二进制最低位到最大值的二进制最高位。

最大值二进制:1000 最小值二进制:0100 说明存在 1000 ^ 0111  = 1111

最大值二进制:1001 最小值二进制:0010 同理

如果二者最高位相同,则比较下一位,直到出现不同的二进制位置,那么从这一位置开始往后到二进制的最低位,存在全为一的最大值,之前的高位置都相同,异或结果为0。

最大值二进制:110010 最小值二进制:110001 说明存在异或结果为110011

#include <bits/stdc++.h>
using namespace std;
int main() {
    int t;
    cin >> t;
    for(int i = 0; i < t; i++) {
        long long l, r;
        cin >> l >> r;
        if(l == r)
            cout << 0 << endl;
        else if((l + 1) == r)
            cout << (l^r) << endl;
        else {
            vector<int> left(64, 0);
            vector<int> right(64, 0);
            vector<long long> num(64, 0);
            long long sum = 1;
            int lidx = 0, ridx = 0;
            while(r) {
                num[ridx] = sum;
                right[ridx++] = r % 2;
                r /= 2;
                sum *= 2;
            }
            while(l) {
                left[lidx++] = l % 2;
                l /= 2;
            }
            long long res = 0;
            while(ridx >= 0) {
               if(right[ridx] == left[ridx])
                   ridx -= 1;
                else {
                    while(ridx >= 0) {
                        res = res + num[ridx];
                        ridx -= 1;
                    }
                    break;
                }
            }
            cout << res << endl;
        }
    }
    return 0;
}

 [USACO 2007 Nov G]Sunscreen

每头奶牛都有一个区间范围,有一些数量的药剂,这些药剂使用后可以使奶牛的数值保持在一个值,问最多可以有多少头奶牛的数值保持在自身规定的区间范围

对于药剂的数值,按照从大到小排序,对于奶牛的区间,按照区间最小值从大到小排序,之后遍历奶牛,对于每头奶牛,遍历药剂看是否存在符合条件的药剂,记录结果即可。

#include <bits/stdc++.h>
using namespace std;
struct node {
    int min;
    int max;
};
struct ss{
    int spf;
    int cov;
};
bool cmp1(struct node& a, struct node& b) {
    return a.min > b.min;
}
bool cmp2(struct ss& a, struct ss& b) {
    return a.spf > b.spf;
}
int main() {
    int c, l;
    cin >> c >> l;
    vector<node> p;
    for(int i = 0; i < c; i++) {
        struct node tmp;
        cin >> tmp.min >> tmp.max;
        p.emplace_back(tmp);
    }
    sort(p.begin(), p.end(), cmp1);
    vector<ss> z;
    for(int i = 0; i < l; i++) {
        struct ss tmp;
        cin >> tmp.spf >> tmp.cov;
        z.emplace_back(tmp);
    }
    sort(z.begin(), z.end(), cmp2);
    int res = 0;
    for(int i = 0; i < c; i++) {
        for(int j = 0; j < l; j++) {
            if(z[j].spf >= p[i].min && z[j].spf <= p[i].max && z[j].cov >= 1) {
                res += 1, z[j].cov -= 1;
                break;
            }
        }
    }
    cout << res << endl;
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值