牛客小白月赛79补题python题解记录

牛客小白月赛79_ACM/NOI/CSP/CCPC/ICPC算法编程高难度练习赛_牛客竞赛OJ (nowcoder.com)

A题(很简单的一道题,带点思维吧还是比较好想的)

给定一个数字n,你可以对它进行接下来的操作——

  • 选择数字中任意一个数位删除

例如对1024选择操作百位,数字则变成了124;对1​024选择操作千位,数字则变成了024
我们称一个数字是干净的,当且仅当数字满足以下任意一种情况:

  • 这个数字是偶数且不含前导零
  • 这个数字为空

请问最少需要进行多少次操作,使得数字n变成干净

题目分析:看到这题我们很容易想到只要把最后面的奇数删掉就满足题意了。当然你用状压搜索及各种各样的暴力也能ac 这题数据不大。

ac代码:

import sys

n = int(sys.stdin.readline())
if n % 2 == 0:
    print(0)
elif n < 10:
    print(1)
else:
    ans = 0
    while n % 2 != 0:
        n //= 10
        ans += 1
    print(ans)

B题(较为简单)

链接:牛客小白月赛79/B

有n个正整数,现在,你可以选择将其中一些数放进灵异背包中,使得背包里面所有数的总和为偶数且最大,求能得到的最大值是多少?

注意:如果你不将任何数放进灵异背包,此时背包总和为0

题目分析:这题比赛的时候数据是出锅了的,输入数据是多行,题目描述里面写的是一行  后面改回来了,但这题拿python交的应该第一发都RE了。看看这道题其实我们可以很快想到给的数全是正数直接全加进去  不合法的话减去一个最小的奇数就好。

ac代码(由于比赛出锅,py交了RE了几发后  问了一下出题人数据是不是不在同一行emmmm,果断选择直接拿c++AC了):

#include<iostream>
using namespace std;
const int N = 1e5+5;

int ls[N],n,ans = 0,cnt = 0;

int main()
{
    cin>>n;
    for(int i = 0; i < n; i++){
        cin>>ls[i];
        if (ls[i] % 2 != 0) cnt++;
        ans += ls[i];
    }
    if (cnt % 2 == 0){cout<<ans<<endl; return 0;}
    int mn = 0x3f3f3f;
    for (int i = 0; i < n; i++){
        if(ls[i] % 2 != 0) mn = min(mn,ls[i]);
    }
    cout<<ans - mn<<endl;
    return 0;
}

C题(简单数学题,其实对小白还是有难度的)

题目:C-mex和gcd的乘积_牛客小白月赛79 (nowcoder.com)

题目分析:更具题意我们可以想到选定的区间里的元素如果不为0那么我们的答案一定是零,所以一定要选带0的区间,我们又由gcd(0,0)=0, gcd(0,x) = x, gcd(0,x,....) = 1可知我们要选带0的区间且区间长度为2肯定是最好的,但不要忘了全是0的话答案为0哦,到这这题就AC了,下面代码是暴力的把mex的最大值和gcd可能的最大值枚举了一遍去max。

ac代码:

import sys

n = int(sys.stdin.readline())
l = list(map(int, sys.stdin.readline().split()))
cnt, idx = 0,[]
for i in range(n):
    if l[i] == 0: 
        cnt += 1
        idx.append(i)
if cnt == 0 or cnt == n:
    print(0)
else:
    ls = sorted(l)
    ans = 0
    for i in range(1,n):
        if ls[i] == ls[i-1] or ls[i] == ls[i-1]+1: ans = ls[i]
        else: break
    ans += 1
    for i in idx:
        if i == 0: ans = max(ans,l[i+1])
        elif i == n-1: ans = max(ans,l[i-1])
        else: ans = max(ans,l[i-1],l[i+1])
    print(ans)

D题(这题可以锻炼一下对取模的理解 提供两种解法贪心和bfs最短路)

题目:D-2^20_牛客小白月赛79 (nowcoder.com)

这题的话提供两种解法:贪心和bfs最短路

解法一:贪心

对题意分析可知,我们是要求让僵尸数量被2^{20}整除的最小射击次数,这题我们要注意到,子弹无穷无尽,所以不可能是-1(小问号你是不是有很多朋友),那么我们想被2^{20}整除就是二进制后面有20个0,而我们每次乘以2都可以在后面加个0,所以最多20次就ok了,如果给我们的数二进制是10011111111111,或10111111111101等等,我们会发现加一两次他就进位了,一下子就多了好多0,这时候不够再乘2就好,所以我们贪心的选择对答案贡献率最大的加的次数再乘2补齐20个0就好,只需枚举先加的次数取min就好。

解法一ac代码:

import sys

m = 1<<20
t = int(sys.stdin.readline())
while t > 0:
    t -= 1
    n = int(sys.stdin.readline())
    ans = 20
    for i in range(21):
        tmp,cnt = n+i,0
        if tmp % m == 0:
            ans = min(ans,i)
            continue
        while tmp != 0:
            if not tmp&1 and cnt < 20:
                tmp //= 2
                cnt += 1
                continue
            break
        ans = min(ans, 20 - cnt + i)
    print(ans)

解法二:BFS最短路

在对2^{20}取模的意义下,我们可以建一张图,最终我们要得到答案0,所以我们可以bfs预处理0到所有小于2^{20}的正整数的 dist 对于每一个询问,输出答案就好。关于见图,由于x可以变为x+1和x+x,所以我们不妨让x+1和x+x向x建一条边权为1的边,这样就好了。

解法二ac代码:

import sys
from collections import deque

inf = float("inf")
m = 1<<20
q = deque()
g,dist = {i:[] for i in range(1048580)}, [inf]*1048580
for i in range(m):
    g[(i+1)%m].append(i)
    g[i*2%m].append(i)
q.append(0)
dist[0] = 0
while q:
    x = q.popleft()
    for y in g[x]:
        if dist[y] != inf: continue
        dist[y] = dist[x] + 1
        q.append(y)

t = int(sys.stdin.readline())
while t > 0:
    t -= 1
    n = int(sys.stdin.readline())
    print(dist[n%m])

E题(简单期望加思维?)

这道题我们理解题意后,就能求出只考虑最后七位正确要尝试次数的期望P = 1/6^{7},E=1/p,所以我们的秒数的期望就是n\cdot E,再将各位的m次平方后取个位就好,找规律可以得到 0 到 9 只要我们平方2次后各位结果就不变了,所以 m = \min (m,2)就好,上ac代码:

import sys

def solve():
    n,m = map(int, sys.stdin.readline().split())
    ans = 279936 #期望,即这么多次尝试能对密码,n*ans就是期望的秒数
    if n < 7: 
        print(-1)
        return
    m = min(m,2)
    ans = ans * n % 10
    for i in range(m): ans = ans * ans % 10
    print(ans)
solve()

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

farawaytravelerchy

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

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

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

打赏作者

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

抵扣说明:

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

余额充值