题解 | #打靶#

打靶

https://ac.nowcoder.com/acm/contest/72389/A

A.打靶

 判断一下最少打多少个和最大打多少个,是否包含y即可。
void solve()
{
    int n,m,x,y;
    cin >> n >> m >> x >> y;
    if(x > y) {
        cout << "No" << '\n';
        return;
    }
    if(x + (n - m) >= y) {
        cout << "Yes" << '\n';
    }
    else {
        cout << "No" << '\n';
    }
}

B.小蓝的疑惑

 因为gcd(a,b)=x,则a和b一定是x的倍数,又因为lcm(a,b)=y。所以a直接从x的倍数开始枚举到y即可,b=x*y/a。判断一下x*y是否是a的倍数即可,并且b也要是x的倍数。否则输出-1即可。
void solve()
{
    ll x,y;
    cin >> x >> y;
    ll t = x * y,a = x;
    while(a <= y) {
        ll p = t / a;
        if(t % a == 0 && p % x == 0) {
            cout << a << ' ' << p << '\n';
            return;
        }
        a += x;
    }
    cout << -1 << '\n';
}

C.k级序列

 我们观察到每一个a[i]实际上就对应了b[i]的取值范围,又因为b序列要非递减,因此可以知道当我们这个数之前的那些位置取到的最左端满足要求的位置要比当前这个数的取值最右端还大时,这个序列就一定构造不出来。
void solve()
{
    int n,k,x;
    cin >> n >> k;
    int L = -2e9;
    bool ok = true;
    for(int i = 0;i < n;i ++) {
        cin >> x;
        if(L > x + k + 1) {
            ok = false;
        }
        L = max(L,x - k);
    }
    if(ok) cout << "Yes" << '\n';
    else cout << "No" << '\n';
}

D.Reverse

 我刚开始以为询问不独立,一直在写线段树,后面看到询问独立了就一下子想到了。
 我们翻转一段区间,其实区间内部贡献不变,只有端点贡献发生改变,由于询问独立,考虑每一次操作我们会产生哪些贡献可以O(1)得出,有以下四种情况。
  1.s[l]为'1',s[l - 1]为'1' 贡献+1
  2.s[r]为'1',s[r + 1]为'1' 贡献+1
  3.s[l]为'1',s[r + 1]为'1' 贡献-1
  4.s[r]为'1',s[l - 1]为'1' 贡献-1
 因此答案等于原答案+产生的贡献即可。
void solve()
{
    int n,q;
    cin >> n >> q;
    string s;
    cin >> s;
    s = "0" + s + "0";
    int ans = 0,pre = -1;
    for(int i = 1;i <= n;i ++) {
        if(s[i] == '1' && s[i] - '0' != pre) ans ++;
        pre = s[i] - '0';
    }
    while(q --) {
        int l,r;
        cin >> l >> r;
        int v = 0;
        if(s[r + 1] == '1' && s[r] == '1') v ++;
        if(s[l - 1] == '1' && s[l] == '1') v ++;
        if(s[l - 1] == '1' && s[r] == '1') v --;
        if(s[r + 1] == '1' && s[l] == '1') v --;
        cout << ans + v << '\n';
    }
}

E.Dog vs Cat

 题目看着看着漏了操作后,然后一直wa。
  这个题其实是一个分类讨论题。因为n=1和n=2特殊情况直接判掉即可。
   n=1:若当前数<=1或者是个奇数则Dog赢,否则Cat赢
   n=2:若两个数相等且为0则Dog赢,若最小值不是0,并且最小值等于最大值,则Cat赢。剩下的全是Dog赢
   n>2:若0的个数>=(n + 1) / 2,则没操作就输了,因此输出Dog。否则看所有数和-零的个数是奇数则Dog赢,否则Cat赢。
void solve()
{
    int n;
    cin >> n;
    vector<int> a(n);
    ll s = 0,c = 0;
    for(auto &x :a) {
        cin >> x;
        c += !x;
        s += max(0,x - 1);
    }
    if(n == 1) {
        if(a[0] <= 1 || a[0] % 2) {
            cout << "Dog" << '\n';
        }
        else {
            cout << "Cat" << '\n';
        }
        return;
    }
    else if(n == 2) {
        sort(a.begin(),a.end());
        if(a[0] == a[1] && !a[0]) {
            cout << "Dog" << '\n';
            return;
        }
        if(a[0] && a[0] + 1 == a[1]) {
            cout << "Cat" << '\n';
            return;
        }
        cout << "Dog" << '\n';
        return;
    }
    if(c >= (n + 1) / 2) {
        cout << "Dog" << '\n';
        return;
    }
    s += ((n + 1) / 2 - c);
    if(s & 1) {
        cout << "Dog" << '\n';
    }
    else {
        cout << "Cat" << '\n';
    }
}

F.小蓝的构造


 看到n只有40,因此想到折半状压。
 如果我们确定了前半段状态,意味着我们从大到小枚举间隔的时候,至多会有一个位置不确定,那么我们此时分类讨论即可。若当前01对已经=a[i](i为间隔)了,则我们空缺位填0即可。若当前01对+1=a[i],则空缺位填1即可。否则不可能完成构造。我们这样是基于贪心的构造,因此我们还需要check一下相应间隔的01对数对不对。
void solve()
{
    int n;
    cin >> n;
    vector<int> cons(n + 1,-1);
    vector<int> a(n);
    for(int i = 1;i < n;i ++) {
        cin >> a[i];
    }
    int m = (n + 1) >> 1;
    auto check = [&]() {
        for(int i = n;i > m;i --) {
            cons[i] = -1;
        }
        for(int i = n - 1;i >= 1;i --) {
            int f = -1,c = 0;
            for(int j = 1;j + i <= n;j ++) {
                if(cons[j + i] == -1) {
                    f = j + i;
                }
                else {
                    if(!cons[j] && cons[j + i]) {
                        c ++;
                    }
                }
            }
            if(c == a[i]) {
                if(f != -1) cons[f] = 0;
            }
            else if(c + 1 == a[i]) {
                if(f == -1) return false;
                cons[f] = 1;
            }
            else return false;
        }
        for(int i = 1;i < n;i ++) {
            int c = 0;
            for(int j = 1;j + i <= n;j ++) {
                if(!cons[j] && cons[j + i]) c ++;
            }
            if(c != a[i]) return false;
        }
        return true;
    };
    for(int i = 0;i < (1 << m);i ++) {
        for(int j = 0;j < m;j ++) {
            if(i >> j & 1) cons[j + 1] = 0;
            else cons[j + 1] = 1;
        }
        if(check()) {
            for(int i = 1;i <= n;i ++) {
                cout << cons[i];
            }
            return;
        }
    }
    cout << -1 << '\n';
}
全部评论
f题这样贪心是对的吗?
1 回复 分享
发布于 2023-12-23 14:53 湖南
=a[i](i为间隔)了,为什么空缺位填0,不是填1
点赞 回复 分享
发布于 2024-05-30 09:30 河南

相关推荐

鸿雁于飞:1. 求职定位乱成一锅粥,直接劝退HR 你期望职位同时写了「项目经理/技术经理/交付经理」,这仨岗根本不是一个赛道!项目经理玩流程和干系人,技术经理玩架构和带技术团队,交付经理玩客户和回款,你仨全堆上,HR直接判定「这人自己都不知道自己要干啥,没核心竞争力」,直接扔简历。 ​ 2. 2年多的职业空窗期,一个字不提,纯纯自杀行为 金融行业最看重职业连贯性和背景干净,你2018年5月到2020年8月,整整2年3个月没上班,啥说明都没有!HR直接脑补你是不是有竞业限制、是不是创业失败、是不是有啥背调过不了的问题,直接不敢往下看,首轮就给你筛了,这是最致命的坑! ​ 3. 工作经历纯纯摆烂,干货全藏起来了 你每段工作就写个公司、职位、时间,干了啥、带了多大团队、出了啥核心成果、给公司赚了/省了多少钱,一个字没有,全堆到后面的项目里了。HR看简历就3秒,第一眼看不到你每段工作的价值,直接就划走了,根本不会翻你后面的项目。 ​ 4. 项目经验像个大杂烩,还全是bug 你堆了快10个项目,银行、证券、公安、政务、日本项目啥都有,跟个杂货铺一样,HR根本看不到你的核心优势在哪。而且项目连个起止时间都不写,谁知道你这是最近的标杆项目,还是10年前刚入行干的活?还有数据前后矛盾,一会说「零事故交付」,一会说「生产事故率降低50%」,HR一看就觉得你瞎包装,根本不信。 ​ 5. 15年经验的经理岗,还在写一线拧螺丝的活,层级完全错配 你都应聘经理级岗位了,简历里还在写自己写接口、写测试脚本、做前端开发这些一线执行的活,完全没写你怎么搭建管理体系、怎么带团队、怎么搞定甲方、怎么控项目风险、怎么拿经营结果,MBA的价值一点没体现出来。HR看完直接觉得:合着你干了15年,还是个高级开发,根本达不到经理岗的要求,直接pass。 ​ 6. AI风口完全没抓住,写了句空话等于没写 现在全行业都在卷AI+金融,人家招管理岗,都要能落地AI场景的人。你就写了句「深化Transformer与大模型底层技术研习」,纯纯空话,一点实际落地成果都没有,跟其他候选人比,完全没差异化优势,人家凭啥放着年轻能落地的不要,要你这个只学了理论的? 姐好好看看,然后改改简历吧,要专,要精,然后降低求职目标。希望你能早日拿到offer
点赞 评论 收藏
分享
评论
7
收藏
分享

创作者周榜

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