这一题其实思路上还是比较简单的,显然任何一个图都可以拆分为以下三个部分:
因此,我们总可以将所有的城市关系分为下述三种:
因此,我们只需要分类讨论上述三种情况下的各个distance的种数然后相加即可。
首先,对于环内的两个城市,这个是比较简单的,对于任何一个距离,从任何一个城市出发,从左从右都可以到达一个城市,因此,任何一个距离 d ≤ ⌊ n 2 ⌋ d \leq \lfloor \frac{n}{2} \rfloor d≤⌊2n⌋的距离都对应 2 n 2n 2n的走法,唯一需要注意一下的就是 n n n为奇数的情况,此时对于 ⌊ n 2 ⌋ \lfloor \frac{n}{2} \rfloor ⌊2n⌋的距离下,左右走到的都是同一个城市,因此需要修正为 n n n。
然后,对于第二种情况,对于环外的两个城市,显然我们将环视为两个节点即可,此时就是一条单链,任意距离 d d d对应的走法总数就是 n − d n-d n−d。不过,我们需要注意一下,因为环上的两个点事实上是不允许走到的,因此我们需要额外刨除一下以这两个点作为起点以及终点时的情况。
最后,对于第三种情况,则稍微复杂一点,显然,我们只需要考虑一侧进入到环的情况即可,此时我们不难按照1中的情况获得从环的入口到达环上任意一点的走法种数,然后,我们对环入口线段上的所有点进行一下累加即可,对应情况极为:
a b c d e a b c d e a b c d e a b c d e ⋯ \begin{aligned} a && b && c && d && e \\ && a && b && c && d && e \\ && && a && b && c && d && e \\ && && && a && b && c && d && e \\ && && && && && && && &\cdots \end{aligned} abacbadcbaedcbedcede⋯
这个我们用一个累积数组进行计算即可。
当然,这里也有一个特殊情况,就是当环的起点和终点是同一个点时,此时走环反而要多走一步,因此我们直接需要过滤掉这种情况。
给出python代码实现如下:
class Solution:
def countOfPairs(self, n: int, x: int, y: int) -> List[int]:
x, y = (x, y) if x <= y else (y, x)
if x == y:
return [2*(n-1-i) for i in range(n)]
inside = y-x+1
left, right = x-1, n-y
def cal_outer(a, b):
m = a+b+2
ans = [2*(m-1-i) for i in range(m)]
for i in range(a):
ans[i] -= 2
ans[i+1] -= 2
for i in range(b):
ans[i] -= 2
ans[i+1] -= 2
ans[0] -= 2
return ans + [0] * (n-len(ans))
def cal_inner(m):
if m % 2 == 0:
ans = [m*2 for i in range(1, m//2)] + [m]
else:
ans = [m*2 for i in range(1, (m+1)//2)]
return ans + [0] * (n-len(ans))
def cal_cross(a, b):
ans= [0 for _ in range(n)]
if a == 0:
return ans
s = [1] + [2 for _ in range((b-1)//2)]
if b % 2 == 0:
s = s + [1]
m = len(s)
s = [0] + list(accumulate(s))
for i in range(a+m-1):
ans[i] = 2*(s[min(i+1, m)] - s[max(0, i-a+1)])
return ans
inner = cal_inner(inside)
outer = cal_outer(left, right)
left_cross = cal_cross(left, inside)
right_cross = cal_cross(right, inside)
ans = [inner[i]+outer[i]+left_cross[i]+right_cross[i] for i in range(n)]
return ans
提交代码评测得到:耗时691ms,占用内存36.1MB。