Analysis: Luxury River Cruise by Nathan Pinsker


We will always apply our sequence of M instructions as a set. We can therefore calculate, for each port of our graph, where we arrive after applying instructions when starting at that port. This takes O(N*M) time. Once we have done this, we obtain a graph of directed edges between vertices representing ports, where an edge from port A to port B means a sequence of M instructions starting at port A leads to port B. This graph is one where each vertex has exactly one outgoing edge. It can be shown that the graph is structured as one or more components, each of which is a single cycle with several trees feeding into it. We are starting at some vertex in this graph, meaning that we only care about the connected component that the vertex is in.

If K is very large, we cannot traverse K edges to find out which port we will arrive at last. However, we can note that we will traverse the cycle in K's component many times. Let C be the length of our cycle. Therefore, we can just take K modulo C to reduce the number of edges we must traverse to a reasonable number. More precisely, we know that we will be in our cycle after traversing N edges, so if K > N, we know that traversing N + (K - N) modulo C edges is equivalent to traversing K edges. This is a reasonable number (at most 2*N) so we can compute this directly. The total runtime is O(N*M) time due to our construction of the graph at the beginning, which is easily fast enough.

Mark Gordon's code is below:
/*
LANG: C++
*/
#include 
#include 
#include 

using namespace std;

#define MAXN 1000

int N, M;
long long K;
string S;
int L[MAXN];
int R[MAXN];

pair get_next(pair v) {
  return make_pair((S[v.second] == 'L' ? L : R)[v.first], (v.second + 1) % M);
}

int main() {
  freopen("cruise.in", "r", stdin); 
  freopen("cruise.out", "w", stdout);

  cin >> N >> M >> K;
  K *= M;
  for(int i = 0; i < N; i++) {
    cin >> L[i] >> R[i];
    L[i]--; R[i]--;
  }
  for(int i = 0; i < M; i++) {
    string s; cin >> s;
    S += s;
  }
  
  pair s0(0, 0);
  pair s1(0, 0);
  for(; K > 0; K--) {
    s0 = get_next(s0);
    s1 = get_next(get_next(s1));
    if(s0 == s1) {
      K--;
      break;
    }
  }
  if(K) {
    int rho = 1;
    for(s0 = get_next(s0); s0 != s1; rho++) {
      s0 = get_next(s0);
    }
    K %= rho;
  }
  for(; K > 0; K--) {
    s0 = get_next(s0);
  }
  cout << s0.first + 1 << endl;
  return 0;
}