题解 | 牛客周赛 Round 56

久违的 场,

A. 面包店故事

思路

判断 的大小关系即可, 不小于 输出 ,否则为

代码实现

// Problem: 面包店故事
// Contest: NowCoder
// URL: https://ac.nowcoder.com/acm/contest/88392/A
// Memory Limit: 524288 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
using namespace std;

#define int long long

void solve()
{
    int x, y, n;
    cin >> x >> y >> n;
    cout << (n >= x + y ? "YES" : "NO");
}

signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);

    int T = 1;
    // cin >> T;
    while (T--) {
        solve();
    }
}

B. 放课后故事

思路

若纸的总数为 ,那么折出来的纸飞机最多有 个。

因为 个人留下与小 一起放飞机,所以放飞机人数为 人。

能分到纸飞机的最多人数即为上述两个值的较小值。

代码实现

// Problem: 放课后故事
// Contest: NowCoder
// URL: https://ac.nowcoder.com/acm/contest/88392/B
// Memory Limit: 524288 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
using namespace std;

#define int long long

void solve()
{
    int n, m, k, s = 0;
    cin >> n >> m >> k;
    for (int i = 1; i <= n; i++) {
        int x;
        cin >> x;
        s += x;
    }
    int ans = min(m + 1, s / k);
    cout << ans;
}

signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);

    int T = 1;
    // cin >> T;
    while (T--) {
        solve();
    }
}

C. 异或故事

思路

因为 ,所以 的一组非负整数解可以为

因为题目要求的是正整数解,所以考虑从低到高枚举二进制位,把 某个二进制位从 修改为 ,然后 该二进制位对应的进行修改,使得异或后仍为 ,此时就是一组正整数解了。

  • 如果 的第 位二进制位为 ,若 的该位为 ,因为 ,则 的该位也需要为 。因为 初始值等于 ,该位置初始为 ,变成 后增加了 , 判断是否超过 ,如果不超过则该情况为可行解。

  • 如果 的第 位二进制位为 ,若 的该位为 ,因为 ,则 的该位也需要为 。因为 初始值等于 ,该位置初始为 ,变成 后减少了 , 判断是否不小于 ,如果不小于 则该情况为可行解。

代码实现

// Problem: 异或故事
// Contest: NowCoder
// URL: https://ac.nowcoder.com/acm/contest/88392/C
// Memory Limit: 524288 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
using namespace std;

#define int long long

void solve()
{
    int a;
    cin >> a;
    int b = a, c = 0, inf = 1e9;
    for (int i = 0; i <= 31; i++) {
        int x = (a >> i) & 1;
        int w = 1 << i;
        if (x == 0) {
            if (b + w <= inf) {
                c += w;
                b += w;
                break;
            }
        } else {
            if (b - w >= 1) {
                b -= w;
                c += w;
                break;
            }
        }
    }
    cout << b << ' ' << c << '\n';
}

signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);

    int T = 1;
    cin >> T;
    while (T--) {
        solve();
    }
}

D. 构造故事

思路

如果选择的三条边从小到大分别为 ,那么当 时构成三角形。

从小到大对 进行排序,然后枚举 ,因为要周长最大,所以 取不超过 的最大值,即为 即为数组 中小于 的最大值。因为数组已经升序,所以可以二分查找 。取 的最大值即为答案。

代码实现

// Problem: 构造故事
// Contest: NowCoder
// URL: https://ac.nowcoder.com/acm/contest/88392/D
// Memory Limit: 524288 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
using namespace std;

#define int long long

const int N = 1e4 + 5;

int n;
int a[N];

void solve()
{
    cin >> n;
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
    }
    sort(a + 1, a + 1 + n);

    int ans = -1;
    for (int i = 2; i < n; i++) {
        int l = i + 1, r = n;
        // 因为升序排列,所以最大边一定在 i 的右边
        while (l < r) {
            int mid = (l + r + 1) >> 1;
            if (a[i - 1] + a[i] > a[mid])
                l = mid;
            else
                r = mid - 1;
        }
        // 判断是否构成三角形
        if (a[i - 1] + a[i] > a[r]) {
            ans = max(ans, a[i - 1] + a[i] + a[r]);
        }
    }
    cout << ans << '\n';
}

signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);

    int T = 1;
    cin >> T;
    while (T--) {
        solve();
    }
}

E. 约会故事

思路

对于时间,可以都转换成分钟,这样方便比较大小,用于比较是否到电影院时间晚,比较是否在 前发送。

然后开心的时间段直接开个数组对时间段内的时间标记,这样在查询的时候就可以直接判断某个时间点是否开心。

注意时间段不一定是开始时间不一定小于结束时间,如果开始时间小于结束时间则直接从开始时间标记到结束时间即可,否则就是跨天的情况,要从开始时间标记到 ,再从 标记到结束时间。

快速查询奶茶名字是否是给出的奶茶名字,可以用 中的 或者 存储然后用 方法查询。

对各个条件判断后综合起来输出即可。

代码实现

// Problem: 约会故事
// Contest: NowCoder
// URL: https://ac.nowcoder.com/acm/contest/88392/E
// Memory Limit: 524288 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
using namespace std;

#define int long long

int n, m, q;
int a[4000];
set<string> st;

void solve()
{
    cin >> n >> m;
    for (int i = 1; i <= n; i++) {
        string s1, s2;
        cin >> s1 >> s2;
        int h1 = stoi(s1.substr(0, 2));
        int m1 = stoi(s1.substr(3, 2));
        int t1 = h1 * 60 + m1;
        int h2 = stoi(s2.substr(0, 2));
        int m2 = stoi(s2.substr(3, 2));
        int t2 = h2 * 60 + m2;
        if (t1 < t2) {
            for (int j = t1; j <= t2; j++)
                a[j] = 1;
        } else {
            for (int j = t1; j <= 3600; j++) {
                a[j] = 1;
            }
            for (int j = 0; j <= t2; j++) {
                a[j] = 1;
            }
        }
    }

    for (int i = 1; i <= m; i++) {
        string s;
        cin >> s;
        st.insert(s);
    }
    cin >> q;
    while (q--) {
        string s, s1, s2, s3;
        cin >> s >> s1 >> s2 >> s3;
        int h = stoi(s.substr(0, 2));
        int m = stoi(s.substr(3, 2));
        int t = h * 60 + m;
        int h1 = stoi(s1.substr(0, 2));
        int m1 = stoi(s1.substr(3, 2));
        int t1 = h1 * 60 + m1;
        int h2 = stoi(s2.substr(0, 2));
        int m2 = stoi(s2.substr(3, 2));
        int t2 = h2 * 60 + m2;

        if (t > 60 + 59) {
            cout << "Loser xqq\n";
            continue;
        }
        if (a[t] && t1 <= t2 && st.count(s3)) {
            cout << "Winner xqq\n";
        } else if (a[t] && (t1 > t2 || !st.count(s3))) {
            cout << "Joker xqq\n";
        } else {
            cout << "Loser xqq\n";
        }
    }
}

signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);

    int T = 1;
    // cin >> T;
    while (T--) {
        solve();
    }
}

F. 不是烤串故事

思路

枚举反转区间的右端点 ,如果反转区间 得到的 公共前缀的最大长度为 ,那么 长度不超过 的前缀也是与 的公共前缀,具有二段性,可以考虑二分 ,取 最大的最小下标 即为答案。

如果将 区间为 的前缀进行反转,得到字符串 ,那么 的前缀有两种情况。

前缀的右边界下标为

  • ,此时
  • ,此时

因为要取未反转和反转后的 的子串,且可以发现,子串反转后是整个父串反转后的子串,所以可以处理 未反转和 整体反转的前缀哈希值,这样就可以直接查询某一段子串未反转或反转后的哈希值。

根据上面讨论的情况对计算拼接后的哈希值,就可以得到反转区间 之后的 (即 ) 某个前缀的哈希值,与 相同长度的前缀哈希值进行比较,即可判断出该前缀是否为公共前缀,从而确定二分时移动左边界还是右边界,最后二分出来的结果即为

代码实现

// Problem: 不是烤串故事
// Contest: NowCoder
// URL: https://ac.nowcoder.com/acm/contest/88392/F
// Memory Limit: 1048576 MB
// Time Limit: 4000 ms
//
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
using namespace std;

// 宏定义
#define fs first
#define sc second

typedef long long ll;
// hashv为双哈希值
typedef pair<ll, ll> hashv;

// 进制和模数
const ll base = 13331;
const ll mod1 = 1e9 + 7, mod2 = 1e9 + 9;

// 下面四个函数重载了两个hashv间的 +,-,*,==
hashv operator+(hashv a, hashv b)
{
    ll c1 = a.fs + b.fs, c2 = a.sc + b.sc;
    if (c1 >= mod1)
        c1 -= mod1;
    if (c2 >= mod2)
        c2 -= mod2;
    return make_pair(c1, c2);
}

hashv operator-(hashv a, hashv b)
{
    ll c1 = a.fs - b.fs, c2 = a.sc - b.sc;
    if (c1 < 0)
        c1 += mod1;
    if (c2 < 0)
        c2 += mod2;
    return make_pair(c1, c2);
}

hashv operator*(hashv a, hashv b)
{
    ll c1 = a.fs * b.fs, c2 = a.sc * b.sc;
    if (c1 >= mod1)
        c1 %= mod1;
    if (c2 >= mod2)
        c2 %= mod2;
    return make_pair(c1, c2);
}

bool operator==(hashv a, hashv b)
{
    return (a.fs == b.fs) && (a.sc == b.sc);
}

// 下面三个函数重载了 hashv 与 ll 间的 +,-,*
// 单个整数会与hashv的两个值都进行运算
hashv operator+(hashv a, ll b)
{
    ll c1 = a.fs + b, c2 = a.sc + b;
    if (c1 >= mod1)
        c1 -= mod1;
    if (c2 >= mod2)
        c2 -= mod2;
    return make_pair(c1, c2);
}

hashv operator-(hashv a, ll b)
{
    ll c1 = a.fs - b, c2 = a.sc - b;
    if (c1 < 0)
        c1 += mod1;
    if (c2 < 0)
        c2 += mod2;
    return make_pair(c1, c2);
}

hashv operator*(hashv a, ll b)
{
    return make_pair(a.fs * b % mod1, a.sc * b % mod2);
}

const int N = 3e6 + 5;

int n;
int val[N];
char str[N], str1[N];
// 预处理的n次方
hashv p[N];

// h1为字符串从左到右的哈希值,h2为字符串从右到左的哈希值
hashv h1[N], h2[N], h3[N];

// op表示方向,op=0表示从左到右,op=1表示从右到左
// 该函数用于得到[l,r]的哈希值
hashv gethash(int l, int r, int op)
{
    if (!op)
        return h1[r] - h1[l - 1] * p[r - l + 1];
    return h2[l] - h2[r + 1] * p[r - l + 1];
}

int check(int id, int id1)
{
    if (!id)
        return 1;
    if (id <= id1) {
        return gethash(id1 - id + 1, id1, 1) == h3[id];
    } else {
        hashv v = gethash(1, id1, 1);
        hashv v1 = gethash(id1 + 1, id, 0);
        hashv v2 = v * p[id - id1] + v1;
        return v2 == h3[id];
    }
}

void solve()
{
    cin >> n >> str + 1 >> str1 + 1;
    for (int i = 1; i <= n; i++) {
        h1[i] = h1[i - 1] * base + (str[i] - 'a' + 1);
    }
    for (int i = n; i >= 1; i--) {
        h2[i] = h2[i + 1] * base + (str[i] - 'a' + 1);
    }
    for (int i = 1; i <= n; i++) {
        h3[i] = h3[i - 1] * base + (str1[i] - 'a' + 1);
    }
    int ans = 1;
    for (int i = 1; i <= n; i++) {
        int l = 0, r = n;
        while (l < r) {
            int mid = (l + r + 1) >> 1;
            if (check(mid, i))
                l = mid;
            else
                r = mid - 1;
        }
        val[i] = l;
        if (val[ans] < val[i])
            ans = i;
    }
    cout << val[ans] << ' ' << ans << '\n';
}

signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);

    // 预处理幂次
    for (int i = 0; i < N; i++) {
        if (!i)
            p[i] = { 1ll, 1ll };
        else
            p[i] = p[i - 1] * base;
    }

    int T = 1;
    cin >> T;
    while (T--) {
        solve();
    }
}
全部评论

相关推荐

不愿透露姓名的神秘牛友
07-07 13:15
点赞 评论 收藏
分享
认真搞学习:28小登的建议,投算法岗不要写什么物理竞赛,互联网+,多写点项目,用什么算法做了什么。还有本科算法是不可能的开发你这个也没有项目啊
点赞 评论 收藏
分享
避坑恶心到我了大家好,今天我想跟大家聊聊我在成都千子成智能科技有限公司(以下简称千子成)的求职经历,希望能给大家一些参考。千子成的母公司是“同创主悦”,主要经营各种产品,比如菜刀、POS机、电话卡等等。听起来是不是有点像地推销售公司?没错,就是那种类型的公司。我当时刚毕业,急需一份临时工作,所以在BOSS上看到了千子成的招聘信息。他们承诺无责底薪5000元,还包住宿,这吸引了我。面试的时候,HR也说了同样的话,感觉挺靠谱的。于是,我满怀期待地等待结果。结果出来后,我通过了面试,第二天就收到了试岗通知。试岗的内容就是地推销售,公司划定一个区域,然后你就得见人就问,问店铺、问路人,一直问到他们有意向为止。如果他们有兴趣,你就得摇同事帮忙推动,促进成交。说说一天的工作安排吧。工作时间是从早上8:30到晚上18:30。早上7点有人叫你起床,收拾后去公司,然后唱歌跳舞(销售公司都这样),7:55早课(类似宣誓),8:05同事间联系销售话术,8:15分享销售技巧,8:30经理训话。9:20左右从公司下市场,公交、地铁、自行车自费。到了市场大概10点左右,开始地推工作。中午吃饭时间大约是12:00,公司附近的路边盖饭面馆店自费AA,吃饭时间大约40分钟左右。吃完饭后继续地推工作,没有所谓的固定中午午休时间。下午6点下班后返回公司,不能直接下班,需要与同事交流话术,经理讲话洗脑。正常情况下9点下班。整个上班的一天中,早上到公司就是站着的,到晚上下班前都是站着。每天步数2万步以上。公司员工没有自己的工位,百来号人挤在一个20平方米的空间里听经理洗脑。白天就在市场上奔波,公司的投入成本几乎只有租金和工资,没有中央空调。早上2小时,晚上加班2小时,纯蒸桑拿。没有任何福利,节假日也没有3倍工资之类的。偶尔会有冲的酸梅汤和西瓜什么的。公司的晋升路径也很有意思:新人—组长—领队—主管—副经理—经理。要求是业绩和团队人数,类似传销模式,把人留下来。新人不能加微信、不能吐槽公司、不能有负面情绪、不能谈恋爱、不能说累。在公司没有任何坐的地方,不能依墙而坐。早上吃早饭在公司外面的安全通道,未到上班时间还会让你吃快些不能磨蹭。总之就是想榨干你。复试的时候,带你的师傅会给你营造一个钱多事少离家近的工作氛围,吹嘘工资有多高、还能吹自己毕业于好大学。然后让你早点来公司、无偿加班、抓住你可能不会走的心思进一步压榨你。总之,大家在找工作的时候一定要擦亮眼睛,避免踩坑!———来自网友
qq乃乃好喝到咩噗茶:不要做没有专业门槛的工作
点赞 评论 收藏
分享
评论
1
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务