CF1560F1/F2 Nearest Beautiful Number

思路

开始蠢了,复杂度写假了。本质直接暴力贪心就行,根本不用枚举到底用了哪些数。

题目要找最小,在满足k限制的情况下可以选n的最长前缀,保证从最小的数找起。如果n本身就满足k限制,则n即为答案。反之取最长前缀,此时确定所用的k个数,在此基础上确定后面的数位上的数。如果没有能满足大于的数(最长前缀后第一位选取的数一定与n不同,否则最长前缀可以延长),则需要将前缀部分+1,后面补0,得到新的n重新找答案(此时保证新的答案最小,可以证明这样的操作至多进行log10n次)。如果有满足大于的数,则后面的所有位取k个数中的最小即可。

总复杂度为O((log10n)2)

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
def lower_bound(nums,x):
for i in range(len(nums)):
if nums[i]>=x:
return i
return -1

def check(n,k,num,pos,_n,wid):
x=num
nums=dict()
while x>0:
nums.setdefault(x%10,0)
x//=10
nums=list(nums.keys())
nums.sort()
flag=0
for i in range(pos,wid):
tmp=int(_n[i])
x=lower_bound(nums,tmp) if flag==0 else 0
if x==-1:
return -1
if flag==0 and nums[x]>tmp:
flag=1
num=num*10+nums[x]
return num

def work(n,k):
res=10**11
_n=str(n)
wid=len(_n)
vis=dict()
tmp=0
cnt=0
for i in range(wid):
num=int(_n[i])
vis.setdefault(num,0)
if vis[num]==1:
tmp=tmp*10+num
continue
if cnt==k:
res=check(n,k,tmp,i,_n,wid)
if res==-1:
return work((tmp+1)*(10**(wid-i)),k)
return res
cnt+=1
vis[num]=1
tmp=tmp*10+num
return tmp

_t=int(input())
for _c in range(_t):
n,k=map(int,input().split())
print(work(n,k))