#!/usr/bin/env python3 # Idea of this solution: # Use a DP table DP[k][i][j] storing the minimum total wait time for the first i A trains and j B trains, # assuming for k=0 that A[i] departs on time and for k=1 that B[j] departs on time. # # There are a few possible 'transitions' between trains: # After A[i] departs at time t: # - The next train is A[i+1]: # - A[i+1] departs at later time A[i+1]>t. # => This can use the DP recursion since A[i+1] departs at its 'natural' time. # - A[i+1]<=t also departs at time t. # => This can not use the recursion, since A[i+1] has to wait before leaving. # - The next train is B[j+1], which can leave either at time A[i]+L or later. # # To handle the case where trains for a 'chain' without any waiting, and where # all trains leave at non-natural times, we must do an additional recursion for # each DP state, where we start with a train for A, then send all waiting B # trains as soon as it arrives, then send all waiting A trains as soon as that B # train is back, ... . # After each step, we allow the chain to be 'broken' by waiting for the next train on the same side. # # FASTER: this immediately finds all trains from a side that depart before time # t, instead of adding them one by one. n, L = map(int, input().split()) a = [-1] b = [-1] for _ in range(n): x, y = input().split() if x == "N": a.append(int(y)) else: b.append(int(y)) A = len(a) B = len(b) INF = 10**18 dp = [[[INF] * (B + 1) for _ in range(A + 1)] for _ in range(2)] dp[0][1][0] = 0 dp[1][0][1] = 0 # DP[0][i][j] min total wait time for first i A's and j B's, with the last A train leaving on time. # DP[1][i][j] min total wait time for first i A's and j B's, with the last B train leaving on time. # # DP[0][i][j] is only valid if A[i] >= B[j]+L, ie we cannot have started any B # train that would end after the current A-start time. # # In state DP[0][i][j] with i > 0, train A[i] departs on time. # Following states: # - Train A[i+1] departs on time. cost 0 # - Train B[x] departs on time, with B[x] the first element >= A[i]+L. B[j+1]...B[x-1] are delayed. # - B[x] departs as soon as A[i] arrives there. Then A[y] departs as s # # 'Push'-DP: once we visit a state it's already correct. def chain(k, i, j, t, cost): if k == 0: # Train A[i] departs at time t. assert 0 < i and i < A # Are more trains ready by time t? while i + 1 < A and a[i + 1] <= t: cost += t - a[i] i += 1 # No chaining needed; a[i] can leave on time. if a[i] > t: dp[k][i][j] = min(dp[k][i][j], cost) return # a[i] wait until time t cost += t - a[i] # a[i] is the last train to wait till t. a[i+1] > t can go for free. dp[k][i + 1][j] = min(dp[k][i + 1][j], cost) # Send a B train right after this A train. if j + 1 < B: # TODO: Directly send all B trains that finish by time t+L. # While loop is faster than recursion. chain(1 - k, i, j + 1, t + L, cost) else: # Train B[j] departs at time t. assert 0 < j and j < B # Are more trains ready by time t? while j + 1 < B and b[j + 1] <= t: cost += t - b[j] j += 1 # No chaining needed; b[j] can leave on time. if b[j] > t: dp[k][i][j] = min(dp[k][i][j], cost) return # b[j] wait until time t cost += t - b[j] # b[j] is the last train to wait till t. b[j+1] > t can go for free. dp[k][i][j + 1] = min(dp[k][i][j + 1], cost) # Send an A train right after this B train. if i + 1 < A: # TODO: Directly send all A trains that finish by time t+L. # While loop is faster than recursion. chain(1 - k, i + 1, j, t + L, cost) for i in range(A): for j in range(B): if i > 0 and dp[0][i][j] < INF: chain(0, i, j, a[i], dp[0][i][j]) if j > 0 and dp[1][i][j] < INF: chain(1, i, j, b[j], dp[1][i][j]) print(min(dp[0][A][B - 1], dp[1][A - 1][B]))