牛客周赛Round 1(0703个人复盘AK By Python3完整题解)

题目1:游游画U

题目描述

游游想让你画一个大小为 n 的 "U" ,你能帮帮她吗?
具体的画法见样例说明。

输入描述:

一个正整数 n.
1 ≤ n ≤ 50

输出描述:

共输出 4n行,每行输出一个长度为 4n 的,仅包含 '*' 和 '.' 两种字符的字符串。

样例1: 

输入:

1

输出:

*..*
*..*
*..*
.**.

样例2 :

输入:

2

输出:

**....**
**....**
**....**
**....**
**....**
**....**
.**..**.
..****..

个人题解:

过于简单,就不浪费大家时间了,模拟一下就可以了......

Python代码(AC):

n = int(input())

for i in range(n * 4 - n):
    res = "*" * n + "." * (4 * n - 2 * n) + "*" * n
    print(res)

for i in range(1,n + 1):
    res = "." * i + "*" * n + "." * (n * 2 - i - n)
    res2 = res[::-1]
    print(res + res2)

题目2:游游的数组染色

题目描述

游游拿到了一个数组,其中一些数被染成红色,一些数被染成蓝色。
游游想知道,取两个不同颜色的数,且它们的数值相等,有多少种不同的取法?
我们定义,两种取法如果取的某个数在原数组的位置不同,则定义为不同的取法。

输入描述:

第一行输入一个正整数 n,代表数组的长度。
第二行输入n个正整数 {a_{i}}​,代表数组中的元素。
第三行输入一个长度为 n,仅包含 'R' 和 'B' 两种字符的字符串,第 i个字符为 'R' 代表数组第i个元素被染成红色,为 'B' 代表被染成蓝色。
1 ≤ n ≤ 200000 
1 ≤ {a_{i}}​ ≤ 10^{9}

输出描述:

输出一个整数,代表取数的方案数量。

样例1: 

输入:        

5
1 2 1 2 2
BRRBB

输出:

3

说明1: 

        第一种取法,取第一个数和第三个数,颜色不同且都是1。

        第二种取法,取第二个数和第四个数,颜色不同且都是2。

        第三种取法,取第二个数和第五个数,颜色不同且都是2。

样例2 :

输入:        

3
2 3 3
BBB

输出:

0

说明2: 

        所有数都是蓝色,显然取不出两个颜色不同的数。

个人题解:

题目简述:给一个数值数组arr,一个字符串数组strings,现要在字符串数组strings中找两个不同的字符同时保证在arr数组中对应索引处的数值是不同的,问有多少种这样的取法?

个人猜测考察点:maybe...哈希吧,我也不知道考察什么hhh,瞎写就是了....

个人题解(较笨):两个字典(哈希),分别记录B、R两个不同颜色的数出现的个数。从字符串中从左往右依次寻找B/R颜色,再将其对应索引的arr中的数值分别存储到各自的字典中。

答案:

        由于B/R两种不同颜色字符的索引和arr中数值元素的索引相对应,因此diff1和diff0两个字典已经分别存储了各颜色对应的数值的出现次数,字典中的键是arr中的数值,值是出现次数;那么本题的答案就是两个不同字典(不同颜色)的相同数值(数值相等)的值的积的和。(注意这个数值一定是要在两个字典中同时存在才可以,其他情况continue就可以了)

Python代码(AC):

import sys 
input = sys.stdin.readline

def main():
    n = int(input())
    arr = list(map(int,input().split()))
    string = input()
    
    # 处理1 0
    diff1 = dict()
    diff0 = dict()
    for i in range(n):
        if string[i] == "B":
            diff1[arr[i]] = diff1.get(arr[i],0) + 1
            
        if string[i] == "R":
            diff0[arr[i]] = diff0.get(arr[i],0) + 1

    # 计算
    res = 0
    for d in diff1:
        if d not in diff0: continue 
        tmp = diff1[d] * diff0[d]
        res += tmp
    print(res)

        
main()

题目3:游游的交换字符

题目描述

游游拿到了一个01串(仅由字符'0'和字符'1'构成的字符串)。游游每次操作可以交换两个相邻的字符,例如,对于字符串"11001"而言,游游可以交换第二个字符和第三个字符变成"10101"。
游游希望最终字符串任意两个相邻的字符都不相同,她想知道最少需要多少操作次数?保证答案是有解的,即最终一定能形成任意两个相邻的字符都不相同的字符串。

输入描述:

一行仅由 '0' 、 '1' 组成的字符串,字符串长度 n 满足 2 ≤ n ≤ 200000。

输出描述:

游游使得相邻两个字母不等的最少操作次数。

样例1: 

输入:

11100

输出:

3

说明1: 先交换第三个、第四个字符,得到字符串"11010"。然后交换第二个、第三个字符,得到字符串"10110"。最后交换第四个、第五个字符,得到字符串"10101"。总共交换3次。

样例2 :

输入:

01011

输出:

2

说明2: 先交换前两个字符,得到字符串"10011",然后交换第三个、第四个字符,得到字符串"10101"。

个人题解:

题目简述:给一个01串,可以有x次操作,每一次操作可以交换两个相邻的字符,现希望x次操作完成之后字符串的任意两个相邻的字符都不相同,求最少的操作次数x。

个人猜测考察点:贪心(瞎写)。。在每一步选择最优的操作,通过局部最优解得到全局最优解。

个人题解(不一定最优):定义个solve函数,记录某个字符string放到arr数组(理想位置 并非真的储存)中的最少操作次数,返回值即为最少操作次数ans和字符string在arr中的出现次数。我们的目标是尽可能地让string在arr中(理想)隔空铺满,即计算arr中的真实值string的索引位置与理想位置的索引的差值的绝对值之和ans。

        我们举个例子来说明一下函数的计算方法:假设当前输入字符串arr是 "11001",我们希望将字符'0'放入列表arr1(理想,没有真实存在),理想的列表arr1应该是 "01010"。现在,我们来计算将字符 0 放入列表arr1的最少操作次数ans

        ① 找到字符 0 在输入字符串 arr中的位置,字符 0 在索引 2 和 3 处;

        ② 计算字符 0 在理想位置的索引i,理想位置的索引是 0 和 2;

        ③ 计算字符 0 在输入字符串arr中出现的位置与理想位置的索引之间的距离:

                a. 第一个字符 0:索引差为 2 - 0 = 2;

                b. 第二个字符 0:索引差为 3 - 2 = 1;

        ④ 将字符 0 在输入字符串中的距离之和累加:ans = 2 + 1 = 3。

        因此对于输入字符串 "11001",将字符 0 放入列表a的最少操作次数是 3 次。

答案:

        如果字符串arr的长度为偶数的话,说明在字符串中,无论字符 0 和 1 的出现次数如何,我们总是可以通过一定的操作将相邻的字符变成不相同的字符;

        但是如果字符串arr长度为奇数的话,那么字符串arr中的字符 1 和字符 0 必有一者的个数大于另一者,在这种情况下,我们就无法通过贪心放置字符 0 和字符 1,然后取min来满足题意要求。(这其实是我wa了好久的原因 em....好菜)解决办法就是单独拿出来处理。然后就过了。。。

Python代码(AC):

import sys
input = sys.stdin.readline

# 将某个字符string放到arr的最少操作次数 -》 计算与预期位置的索引的差值的绝对值之和
def solve(arr,string):
    ans = 0
    lens = 0 # string 在 arr 中出现的次数
    tmp_ind = 0
    for ind,val in enumerate(arr):
        if val == string:
            ans += abs(ind - tmp_ind)
            tmp_ind += 2      # 理想的位置
            lens += 1         # 目标字符计数
    return ans,lens

def main():
    arr = input().strip()
    n = len(arr)     # 字符串长度
    ans0, len0 = solve(arr, "0")
    ans1, len1 = solve(arr, "1")
    if n % 2 == 0:
        print(min(ans0, ans1))
    else:
        # 奇数长度的话 - 单独处理
        print(ans1 if len1 > len0 else ans0)

main()

题目4:游游的9的倍数

题目描述

游游拿到了一个数字串,她想取一个该数字串的子序列(子序列在原串中可以不连续),使得该子序列是9的倍数。子序列可以包含前导零。
游游想知道,一共能取多少个合法的子序列?答案请对 10^{9} + 7 取模。
我们定义,若两个子序列在原串中的位置不同,则认为它们不同。

输入描述:

一个长度不超过200000的,仅由'0'~'9' 十种字符组成的字符串。

输出描述:

子序列是9的倍数的数量。答案请对 10^{9} + 7 取模。

样例1: 

输入:

1188

输出:

5

说明1: 共可以取4个不同的"18"子序列,和一个"1188"子序列,都是9的倍数。

样例2 :

输入:

0123

输出:

1

说明2: 只有子序列"0"是9的倍数。

个人题解:

题目简述:给一个数字字符串,需要我们找出所有的子序列(含不连续子序列),使得该子序列的数值是9的倍数。求这样的子序列的个数,然后对答案取余即可。

个人猜测考察点:状压DP。。。

个人题解(不一定最优):DP是一个很复杂的知识点,具体步骤如下:(maybe笔者太笨啦hhh推理的有点慢,如有优解,请在评论区共同分享探讨,不胜感激!!)

分三个步骤:

1. 定义状态:dp[i][j]表示以前i个字符为结尾的子序列中,模9后余j的子序列的个数。

2. 初始状态:对于长度为i的子串arr[i],有dp[i][arr[i] % 9] = 1,其余dp[i][j]均为0。

3. 状态转移:对于当前每个新的字符arr[i],有两种选择:要么将其选为新的结尾字符,要么就不选。若将其作为新的结尾字符的话,新的模9后余数应该为(j + arr[i])%9, 那么转移到当前状态的式子应该是:

 dp[i][j] = dp[i-1][(j - arr[i])%9]

若不将其作为新的结尾字符的话,那么当前状态跟上一个状态的子序列个数一致,即转移到当前状态的式子应该是:

dp[i][j] = dp[i-1][j]

综上,状态转移方程可以表示为:

dp[i][j] += dp[i-1][(j - arr[i]) % 9] + dp[i-1][j] 

4. 答案:最终的答案为dp[n-1][0],其中n为数字字符串的长度。

Python代码(AC):

import sys
input = sys.stdin.readline

def solve(arr,Mod = pow(10,9) + 7):
    n = len(arr)
    # dp[i][j]表示以数字串的前i个字符为结尾的子序列中,模9后余j的子序列的个数  =》 dp[i][j] 表示的是满足条件的子序列的个数
    dp = [[0 for i in range(9)] for j in range(n)]
    for i in range(n):
        # 初始状态: 前i个字符结尾的子序列中,模9后余数为j的个数是1个
        dp[i][arr[i] % 9] = 1
        for j in range(9):
            # 将s[i]作为新的结尾字符 当前状态新的模9的余数应该为(j + s[i]) % 9
            dp[i][j] %= Mod
            dp[i][j] = (dp[i][j] + dp[i - 1][j] + dp[i - 1][(j - arr[i]) % 9]) % Mod
    return dp[n - 1][0]

def main():
    arr = list(map(int,input().strip()))
    res = solve(arr)
    print(res)

main()

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值