牛客小白月赛79_ACM/NOI/CSP/CCPC/ICPC算法编程高难度练习赛_牛客竞赛OJ (nowcoder.com)
A题(很简单的一道题,带点思维吧还是比较好想的)
给定一个数字n,你可以对它进行接下来的操作——
- 选择数字中任意一个数位删除
例如对1024选择操作百位,数字则变成了124;对1024选择操作千位,数字则变成了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最短路
解法一:贪心
对题意分析可知,我们是要求让僵尸数量被整除的最小射击次数,这题我们要注意到,子弹无穷无尽,所以不可能是-1
(小问号你是不是有很多朋友),那么我们想被整除就是二进制后面有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最短路
在对取模的意义下,我们可以建一张图,最终我们要得到答案0,所以我们可以bfs预处理0到所有小于
的正整数的 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题(简单期望加思维?)
这道题我们理解题意后,就能求出只考虑最后七位正确要尝试次数的期望,所以我们的秒数的期望就是
,再将各位的m次平方后取个位就好,找规律可以得到 0 到 9 只要我们平方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()