T1:最小字典序
问题描述
时间限制:1.000S 空间限制:256MB
题目描述
小红有一个 01 字符串,她可以进行最多 k 次提作,每次操作可以交换相邻的两个字符,问可以得到的字典序最小的字符串是什么。 输入描述
第一行包含两个整数,n(1 < n < 10^5)和 k(1 < k < 10^9),表示字符串的长度和可以进行的操作次数。
接下来一行一个长度为 n 的 01 字符串。
输出描述
输出一个长度为 n 的字符串,表示字典序最小的字符串。
输入示例
5 2
01010
输出示例
00101
思路
这个题的n的范围是,k的范围是,所以暴力是不可能暴力的。
分析一下规律:
以10101开始分析
k=1:01101
k=2:01011
k=3:00111
k>3:00111
总结起来就是说:从前往后扫,把前面的0尽可能前移
编程过程
Step1:记录前缀和(1的个数)
如 1010101010 ==> 1 1 2 2 3 3 4 4 5 5 我们只需要0对应的位置
前缀和记录的是1的个数,如pre[1] = 1指的是当前的0可以前移1位
pre[5] = 3:当前面两个0前移之后,变成00111 0 1010,此时pre[5]指的是当前的0可以前移3位
Step2:遍历字符串
Case1:`s[idx]=="1"`,idx += 1
Case2:`s[idx]=="0" and pre[idx] > 0`
if k > pre[idx] : 把0移动至最前面
else: 把0前移k-pre[idx]位
即:把K拆解成多个前缀之和,如s=1010101010 k=8 pre= [1 1 2 2 3 3 4 4 5 5]
8 = 1 + 2 + 3 + 2
代码
def fun(n,k,s):
idx = 0
# 前缀和
pre =[0]
for ss in s:
if ss == "1":
pre.append(pre[-1]+1)
else:
pre.append(pre[-1])
# 处理超大K值
_sum = 0
for i,ss in enumerate(s):
if ss == "0":
_sum += pre[i+1]
if k >= _sum:
print("0"*s.count("0") + "1"*s.count("1"))
return
# 举个例子:1010101010 k=8
# 记录一下前缀和:pre: 1 1 2 2 3 3 4 4 5 5
# 前缀和记录的是1的个数,如pre[1] = 1指的是当前的0可以前移1位
# pre[5] = 3:当前面两个0前移之后,变成00111 0 1010,此时pre[5]指的是当前的0可以前移3位
# 我们可以观察到0对应的前缀分别为1 2 3 4 5,那么8 = 1 + 2 + 3 + 2
# 也就是说前三个0前移:0001111010,此时还剩下2次移动,00011 0 11 10
while k > 0 and idx < n:
while (idx < n and s[idx] == "1") or pre[idx+1]<=0: idx += 1
if idx == n: break
if k >= pre[idx+1]:
s = "0"+s[:idx] + s[idx+1:]
k -= pre[idx+1]
pre[idx + 1] = -1
if k == 0: break
else:
s = s[:idx-k] + "0" +s[idx-k:idx] + s[idx+1:]
break
print(s)
n,k = map(int,input().split(" "))
s = input()
fun(n,k,s)
T2:子序列个数
时间限制:1.000S 空间限制:256MB
题目描述
讨厌鬼有一个长度为 n (1 < n < 10^5)的数组,他想知道这个数组有多少个子序列是一个排列?
子序列的定义: 数组删除若干个元素(也可以不删)后得到的新数组。
排列的定义: 长度为 m 的数组,1 到 m 每个元素都出现过,且恰好出现 1 次。
输入描述
第一行输入一个整数 n。
第二行输入 n 个正整数,a1, a2, ..., an。(1 <= ai <= 10^9)
输出描述
一行一个整数,表示有多少个子序列是一个排列。由于答案过大,请将答案对 10^ 9 + 7 取模后输出
输入示例
6
1 1 5 2 3 4
输出示例
10
提示信息
符合要求的子序列有:{1},{1},{1,2},{1,2},{1,2,3},{1,2,3},{1,2,3,4},{1,2,3,4},{1,5,2,3,4},{1,5,2,3,4}共 10 个
思路
以n = 6,nums=1 1 5 2 3 4
为例
cnt = {1:2,2:1,3:1,4:1,5:1}
其实就是计数
1 , 1-2, 1-3, 1-4, 1-5 的个数 ==>2, 2*1, 2*1*1, 2*1*1*2, 2*1*1*1*1 也就是 累乘和,所以又是一道前缀和
代码
from collections import Counter
n = int(input())
nums = list(map(int,input().split(" ")))
dic = Counter(nums)
nums = list(set(nums))
nums.sort()
idx = 1
ans = 0
if dic[1] == 0:
print(0)
else:
pre = [1]
for num in nums:
pre.append((pre[-1]*dic[num])%(10**9+7))
# print(dic)
# print(pre)
while idx <= nums[-1]:
if idx in dic:
ans += pre[idx]
ans = ans %(10**9+7)
idx+=1
else:
break
print(ans)