题目
小蓝最近学习了一些排序算法,其中冒泡排序让他印象深刻。
在冒泡排序中,每次只能交换相邻的两个元素。
小蓝发现,如果对一个字符串中的字符排序,只允许交换相邻的两个字符,在所有可能的排序方案中,冒泡排序的总交换次数是最少的。
例如,对于字符串
lan
排序,只需要 1 次交换。对于字符串qiao
排序,总共需要 4 次交换。小蓝的幸运数字是 V,他想找到一个只包含小写英文字母的字符串,对这个串中的字符进行冒泡排序,正好需要 V 次交换。请帮助小蓝找一个这样的字符串。如果可能找到多个,请告诉小蓝最短的那个。如果最短的仍然有多个,请告诉小蓝字典序最小的那个。请注意字符串中可以包含相同的字符。
输入描述
输入一行包含一个整数V (1≤V≤104),为小蓝的幸运数字。
输出描述
输出一个字符串,为所求的答案。
思路
又是这种字母的排序问题,最短序列也就是全是逆序,但题目中提到字符串中可以包含相同的字符,比之前的更复杂。首先要确定最短的序列有多少个字符,因为是逆序排列,所以不考虑字典序最小,也就是从某个字母开始逆序排列(假设从字母c开始 d为第3位字母 下标从0开始)。交换次数也是(3+2+1+0 = (1+3) * 3 /2 = 6)。但是字典序最小且可以重复就比较复杂了。示例中的:jihgfeeddccbbaa = 14+13+12+11+10+8+8+6+6+4+4+2+2+0+0 = 100
可以看见重复的字母贡献的次数都是偶数且依次递增。
因此总的分两种情况进行考虑。当v刚好等于S= (1+i)*i/2的时候,直接找到第i个字母进行逆序输出。当v不等于S = (1+i)*i/2时,则找到大于v的最小S,确定字符串的长度。重复字母的长度则 = ((i+1)*(i) - 2*v)/2 ,其他位置也逆序输出 比如这里的v=100, 由于(1+14)*14/2 = 105 > 100, 则总的字符串长度为15,几位重复的字母为 a,b,c,d,e(105-100= 5位),其他位置(10-15]的字母为fghij。最后将字符串逆序输出。(描述得好乱,私密马赛)
代码
import os
import sys
# 请在此输入您的代码
v = int(input())
words = 'abcdefghijklmnopqrstuvwxyz'
def get_len(n):
for i in range(2, 1000000):
if (1 + i)* i == 2*n:
return i+1, 0
elif (1 + i) * i > 2 * n:
return i+1, 1
word_len, flag = get_len(v)
# 没有重复字母,直接输出
if flag == 0:
print(words[:word_len][::-1])
# 出现重复字母的情况
else:
t = int((word_len*(word_len - 1) - 2*v)/2) #重复的个数刚好是105-100 = 5 重复( 2(b) 4(c) 6(d) 8(e))
s = ''
t1 = t
x = ''
for i in range(t):
s += words[i]
s += words[i]
for i in range(2*t, word_len):
s += words[t1]
t1 += 1
print(s[::-1])
Tips
list.reverse()没有返回值,直接在原列表上进行逆序排列。
str[::-1] 逆序输出,如果只想逆序输出某部分 str[:3][::-1] 不能直接放在一起写 比如:str[:3:-1]
题目
小蓝发现,他将 1至 1000000007 之间的不同的数与 20212021 相乘后再求除以 1000000007 的余数,会得到不同的数。 小蓝想知道,能不能在 11 至 1000000007 之间找到一个数,与 2021 相乘后 再除以 1000000007 后的余数为 999999999。如果存在,请在答案中提交这个数; 如果不存在,请在答案中提交 0。
思路
根据数学公式进行修改,不用i去一个个遍历,肯定会超时。换成求 1000000007的倍数+999999999 等于2021与某个数相乘。
代码
import os
import sys
# 请在此输入您的代码
flag = 1
for i in range(1,1000):
if (i * 1000000007 + 999999999) % 2021 == 0:
x = (i * 1000000007 + 999999999) / 2021
flag = 0
break
if flag == 0:
print(int(x))
else:
print(0)