OpenJudge - 01037:A decorative fence
题目是英文,先说说大致意思:有一些栅栏,由高度各不相同的木棍组成(1~n的一个全排列),但要求满足条件,某一个木棍必须比其相邻的木棍都要矮或者都要高,换句话说就是要求栅栏必须是波浪形的。然后给出栅栏的木棍个数和根据字典序得到的排位,要求你输出相应栅栏的高度序列。
显然,这道题是和排列有关的,但是加上了一些条件。因此我们应当先求出一些数组,从而可以方便地在求序列的时候使用(类似普通排序的排名的时候用到n!)。
考虑到求序列的时候肯定会用到更短序列的排列数,我们可以很容易地想到动态规划。于是,我们设为第一根木棍长度小于第二根,木棍数量为
,第一根木棍为
根木棍中第
短的时候,所构成的序列的个数;同理,设
为第一根木棍长度大于第二根,木棍数量为
,第一根木棍为
根木棍中第
短的时候,所构成的序列的个数。
显然,使用动态规划就可以得到想要的数组了:
up = [[0 for _ in range(25)] for _ in range(25)]
down = [[0 for _ in range(25)] for _ in range(25)]
up[1][1], down[1][1] = 1, 1
for i in range(2, 21):
for j in range(1, i+1):
for k in range(j, i):
up[i][j] += down[i-1][k]
for k in range(1, j):
down[i][j] += up[i-1][k]
接下来的处理就方便很多了,其实和求普通排序的排名是差不多的思路,都是进行尝试,然后看是否在对应范围内(我描述的不太清楚,直接上代码吧~)
a, used = [0 for _ in range(21)], [False for _ in range(21)]
def solve(n, c):
for i in range(1, n+1):
k = 0
for j in range(1, n+1):
tmp = 0
if not used[j]:
k += 1
if i == 1:
tmp += up[n][k]+down[n][k]
else:
if a[i-1] < j and (i <= 2 or a[i-2] > a[i-1]):
tmp += down[n-i+1][k]
elif a[i-1] > j and (i <= 2 or a[i-2] < a[i-1]):
tmp += up[n-i+1][k]
if tmp >= c:
used[j] = True
a[i] = j
break
else:
c -= tmp
那么以上两点考虑清楚了就可以得到完整代码啦~
def solve(n, c):
for i in range(1, n+1):
k = 0
for j in range(1, n+1):
tmp = 0
if not used[j]:
k += 1
if i == 1:
tmp += up[n][k]+down[n][k]
else:
if a[i-1] < j and (i <= 2 or a[i-2] > a[i-1]):
tmp += down[n-i+1][k]
elif a[i-1] > j and (i <= 2 or a[i-2] < a[i-1]):
tmp += up[n-i+1][k]
if tmp >= c:
used[j] = True
a[i] = j
break
else:
c -= tmp
up = [[0 for _ in range(25)] for _ in range(25)]
down = [[0 for _ in range(25)] for _ in range(25)]
up[1][1], down[1][1] = 1, 1
for i in range(2, 21):
for j in range(1, i+1):
for k in range(j, i):
up[i][j] += down[i-1][k]
for k in range(1, j):
down[i][j] += up[i-1][k]
for _ in range(int(input())):
n, c = map(int, input().split())
a, used = [0 for _ in range(21)], [False for _ in range(21)]
solve(n, c)
for i in range(1, n+1):
print(a[i], end=' ')
print()