牛客周赛Round 56补题

C.异或故事(位运算, 范围)

只过了60%的代码:原因在于最后为了确保b和c不为0的时候,选择了在最高位的上面一位给b和c都加上1,这实际上会有溢出的风险,被卡掉了。

#include<iostream>
#define int long long
using namespace std;

int T;

signed main() {
    cin >> T;
    while (T --) {
        int a, b = 0, c = 0;
        cin >> a;
        int idx = 0;
        bool turn = 1;

        // 处理 a == 1 的特殊情况
        if (a == 1) {
            cout << 2 << " " << 3 << endl;
            continue;
        }

        // 普通情况,交替分配位给 b 和 c
        while (a) {
            if ((a & 1) == 1) {
                if (turn)
                    b |= (1 << idx);
                else
                    c |= (1 << idx);
                turn = !turn;
            }
            idx++;
            a >>= 1;
        }

        // 确保 b 和 c 都不为 0
        if (b == 0 || c == 0) {
            b |= (1 << idx);
            c |= (1 << idx);
        }

        cout << b << " " << c << endl;
    }
    return 0;
}

AC代码一:思路与我类似,1e9对于二进制最高有32bit,对于a的二进制为1的位置上,设置一个turn变量,b和c依次轮流为1,让b和c尽可能接近,不要超过1e9的范围。由于b是第一个设置1的数,所以只有c可能会是0,这里做法不是在最高位的上一位将b和c修改为1,而是找到a最低的0位,将b和c对应位置同时改为1。

#include<iostream>
using namespace std;
int T;
int main(){
    cin >> T;
    while (T --){
        int a, b = 0, c = 0;    cin >> a;
        bool turn = 1;
        for(int i = 0; i < 32; i ++){
            if((a >> i) & 1){
                if(turn)    b |= (1 << i);
                else        c |= (1 << i);
                turn = !turn;
            }
        }
        if (c == 0)
            for(int i = 0; i < 32; i ++){
                if(((a >> i) & 1) == 0){    // 这边注意==的优先级比&更大
                    b |= (1 << i);
                    c |= (1 << i);
                    break;
                }
            }
        cout << b << " " << c << endl;
    }
    return 0;
}

AC代码二:利用异或性质,a ^ b = c  ====>  a ^ c =  b,那么只需要考虑三种情况即可,a = 1时,输出2和3;对于a = 1e9,输出3000和1e9^3000的结果即可(如果为1的话,异或的另一边会超出1e9);其他情况直接输出1和1^a结束。

#include<iostream>
using namespace std;
const int N = 1e9;
int T;
int main(){
    cin >> T;
    while (T --){
        int a, b = 0, c = 0;    cin >> a;
        if(a == 1)    cout << 2 << " " << 3 << endl;
        else if (a == N)    cout << 4000 << " " << (N ^ 4000) << endl;
        else    cout << 1 << " " << (1 ^ a) << endl;    
        // 注意异或运算符优先级是大于 <<的
    }
    return 0;
}

E.约会故事(大模拟)

思路:

        ①一开始写代码写复杂了(时和分钟分开来进行了比较,导致处理比较繁琐),最简单的方式应该全部转化为分钟去处理。

        ②注意给定的快乐时间,题目中没有说一定是在同一天,所以可能出现快乐开始时间大于结束时间的情况,这时候要考虑到第二天。

        ③某个区间都是快乐的,给定起止区间====>利用差分和前缀和简化。注意隔天快乐的设置的方法。

代码:

#include<iostream>
#include<unordered_map>
#include<unordered_set>
using namespace std;
int happy[1500];    // 60 * 24 = 1440 定义为差分数组
unordered_set<string> ld;
int cal(string time){    // 转化为分钟数
    int h = (time[0] - '0') * 10 + (time[1] - '0');
    int m = (time[3] - '0') * 10 + (time[4] - '0');
    return h * 60 + m;
}

int main(){
    int n, m;    cin >> n >> m;
    for(int i = 0; i < n; i ++){
        string st, ed;    cin >> st >> ed;
        int stmin = cal(st), edmin = cal(ed);
        if(stmin == edmin)    happy[0] += 1000;    // 后面求前缀和就可以全部置为happy(true)了
        else if(stmin > edmin){                    // 隔天
            happy[stmin] += 1, happy[0] += 1, happy[edmin + 1] -= 1;
        }else
            happy[stmin] += 1, happy[edmin + 1] -= 1;
    }
    for(int i = 1; i < 120; i ++)    happy[i] += happy[i - 1];    // 求前缀和数组
    
    for(int i = 0; i < m; i ++){
        string d;    cin >> d;
        ld.insert(d);
    }
    int ty;    cin >> ty;
    while (ty --){
        string tytime, xqqtime, ctime;
        cin >> tytime >> xqqtime >> ctime;
        int x1 = cal(tytime);
        int xqqmin = cal(xqqtime), cmin = cal(ctime);
        string tea;    cin >> tea;
        //cout << (xqqmin < cmin) << endl;
        if(x1 < 120 && happy[x1] && ld.count(tea) && xqqmin <= cmin)    cout << "Winner xqq" << endl;
        else if(x1 > 120 || !happy[x1])    cout << "Loser xqq" << endl;
        else if(x1 < 120 && happy[x1] && (ld.count(tea) == 0 || xqqmin > cmin))
                cout << "Joker xqq" << endl;
    }
    return 0;
}

F.不是烤串故事(二分+字符串哈希)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

_Ocean__

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

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

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

打赏作者

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

抵扣说明:

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

余额充值