20220915蚂蚁算法岗笔试题解

不是自己的场,补一下题。

T1

小红和小紫拿到了一个正整数x,她们每次可以选择x的一个因子k(k>1),把x除以k,但要求k必须是素数。
小红先手,谁先不能操作谁输。假设两人都足够聪明,最终谁取得胜利?

共进行t次游戏。
输入描述:
第一行输入一个正整数t,代表游戏的轮数。
接下来的行,每行输入一个正整数x,代表小红和小紫拿到的正整数
1<t<10
1<x<1e9
输出描述:
对于每次游戏:
如果小红获胜,输出一行字符串“kou”
如果小紫获胜,输出一行字符串"yukari”

input:
2
5
12

output:
kou
kou

其实就是对x进行质因子分解,看有多少质因子,根据质因子数量判断胜负。

但是正常质因子分解是O(n)的,x在1e9以内,无法通过。我们可以只判断1e5以内的素数。因为必然不可能存在2个1e5以上的素数乘积乘出来x。如果1e5以内的筛完了,剩下的数字一定一个素数。

for _ in range(int(input())):
    x = int(input())
    c = 0
    while x % 2 == 0:
        c += 1
        x //= 2

    for i in range(3, 100001, 2):
        if x == 1: break
        while x % i == 0:
            c += 1
            x //= i
    if x > 1: c += 1
    print('kou' if c & 1 else "yukari")

T2

题目描述
小红拿到了一个数组,她想知道对于每个k(k∈[1,n]),有多少个长度为k的连续上升子数组?
输入描述:
第一行输入一个正整数n,代表数组的长度。
第二行输入n个正整数ai,代表小红拿到的数组。
1 <n,ai < 2 × 1e5
输出描述:
输出几个正整数,第个正整数代表长度为i的连续上升子数组数量。

input:
5
2 3 4 4 2

output:
5 2 1 0 0

双指针。假设以某元素为结尾可以达到长度为m的连续上升子数组,那么它一定可以达到1、2、3...m-1长度的,计算之后前缀和处理。

n = int(input())
*a, = map(int, input().split())
ans = [0] * (n + 1)
l = 0
pre = -1
for r, v in enumerate(a):
    if v <= pre:
        l = r
    pre = v
    ans[r - l + 1] += 1
for i in range(n - 1, 0, -1): ans[i] += ans[i + 1]
print(*ans[1:])

T3

小红定义一个字符串是好串,当且仅当每个字母出现的次数均为偶数。
小红拿到了一个字符串,她想知道该字符串有多少子序列是好串?
子序列的定义:字符串中按原串顺序取一些字母组成的字符串(在原串中可以不连续)。
例如,"arcaea"的子序列有"aaa"、"ace"等等。
输入描述:
一个长度不超过2e5的、仅由小写字母组成的字符串。
输出描述:
好子序列的数量。
由于答案可能会很大,请对1e9+7取模后再输出。

input:
ababa

output:
7

不难看出,因为要组成的是子序列,只需要判断每个字符出现的次数即可。比如:某字符出现了m次,那么该字符出现在好子序列中的次数必然为0、2、4、6...、m次。因为出现的字符在什么位置并不重要,我们只需要在这所有字符里面任意选0、2...、m个。

根据如上思路,对每一个字符都进行如上处理,可以得到一个:(字符1出现0次+字符1出现2次+...)*(字符2出现0次+字符2出现2+...)*...

可以写出如下代码:

from collections import Counter
from math import factorial

def C(n, m):
    return factorial(n) // (factorial(n - m) * factorial(m))

s = input()
c = Counter(s)
mod = int(1e9 + 7)
if all([v == 1 for v in c.values()]):
    print(0)
else:
    ans = 1
    for v in c.values():
        cnt = 0
        for j in range(0, v + 1, 2):
            cnt += C(v, j)
        ans *= cnt
        ans %= mod

    print((ans - 1 + mod) % mod)

这样会超时,需要推一下公式简化复杂度。推导过程略过不谈,可以证明如下性质,假设某数字为m

  • C(m,0)+C(m,1)+...+C(m,m)=2^m
  • 如果m是偶数:C(m,0)+C(m,2)+C(m,4)+...+C(m,m)=2^(m-1)
  • 如果m是奇数:C(m,0)+C(m,2)+C(m,4)+...+C(m,m-1)=2^(m-1)

可自行证明。

根据如上证明,可以写出

s = input()
mod = int(1e9 + 7)
c = Counter(s)
ans = 1
for v in c.values():
    ans *= pow(2, v - 1, mod)
    ans %= mod
print((ans - 1 + mod) % mod)

看了一眼群友的思路,其实可以再进一步,可以直接算出来:

s = input()
mod = int(1e9 + 7)
print(((1 << (len(s) - len(set(s)))) - 1 + mod) % mod)

但是我不会推)

#蚂蚁金服##蚂蚁##笔试#
全部评论
开发岗第三题也是好串 但是定义不同 定义一个字符串中只有一个字符出现的次数为奇数 其他字符出现偶数次 求给定字符串的子串中的好串个数
点赞 回复 分享
发布于 2022-09-15 21:29 广东
第一题可以筛法把素数都找出来,这样t很大的时候,可以二分查找查表
点赞 回复 分享
发布于 2022-09-16 16:39 北京
我怎么想不到用幂函数呢,傻傻地用C排列组合超时
点赞 回复 分享
发布于 2022-09-15 21:41 广东
大佬有交流群吗,求拉一个
点赞 回复 分享
发布于 2022-09-15 22:31 上海
hi~同学,秋招遇“寒气”,牛客送温暖啦!23届秋招笔面经有奖征集中,参与就得牛客会员7天免费体验,最高赢300元京东卡!戳我去看>>>https://www.nowcoder.com/link/zhengjipinglun
点赞 回复 分享
发布于 2022-09-16 13:05 北京
第三题,len(s)就是sum(mi),len(set(s))就是i的取值范围,根据你之前优化的结果2^m-1就可以得到最后那个直接出结果的表达式
点赞 回复 分享
发布于 2022-09-16 17:12 北京
C(m,0)+C(m,1)+...+C(m,m)=2^m 如果m是偶数:C(m,0)+C(m,2)+C(m,4)+...+C(m,m)=2^(m-1) 如果m是奇数:C(m,0)+C(m,2)+C(m,4)+...+C(m,m-1)=2^(m-1) 公式推导过程是啥?
点赞 回复 分享
发布于 2022-09-19 19:53 北京
T3为什么我算出来是8: from itertools import permutations s = ['a&(30185)#39;, 'b&#39;, 'a&(30185)#39;, 'b&#39;, 'a&(30185)#39;] child_s = [] for i in range(2, len(s), 2):     for j in permutations(s, i):         if(len(j) != 0):             if(list(j) not in child_s):                 child_s.append(list(j)) count = 0 for i in child_s:     for j in range(len(i)):         if(i.count(i[j]) % 2 != 0):             break         else:             if(j == len(i)-1):                 count = count + 1 print(int(count % (1e9+7)))
点赞 回复 分享
发布于 2022-10-03 23:32 浙江

相关推荐

牛客717484937号:双飞硕没实习挺要命的
点赞 评论 收藏
分享
10-31 14:54
已编辑
门头沟学院 算法工程师
点赞 评论 收藏
分享
评论
20
39
分享
牛客网
牛客企业服务