子串排序&&相乘

题目

小蓝最近学习了一些排序算法,其中冒泡排序让他印象深刻。

在冒泡排序中,每次只能交换相邻的两个元素。

小蓝发现,如果对一个字符串中的字符排序,只允许交换相邻的两个字符,在所有可能的排序方案中,冒泡排序的总交换次数是最少的。

例如,对于字符串 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)

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值