Two Strings Game – HackerRank Solution

In this post, we will solve Two Strings Game HackerRank Solution. This problem (Two Strings Game) is a part of HackerRank Problem Solving series.

Solution – Two Strings Game – HackerRank Solution

C++

#include <iostream>
#include <vector>
#include <cstdio>
#include <algorithm>
using namespace std;
 
#define maxn 300000
#define limit 1000000000000000000LL
 
long long k;
 
int n, m, i, j, cur, bad_value, kk;
char a[maxn], b[maxn];
bool was[30];
pair<int, int> srt[maxn * 2 + 3];
 
struct sfa {
 
    long long dp[maxn * 2 + 3], grundy_sum[30], ways[maxn * 2 + 3];
 
    int next[maxn * 2 + 3][26], len[maxn * 2 + 3], lnk[maxn * 2 + 3], grundy[maxn * 2 + 3];
    int nodes, last, j;
 
    void init () {
        nodes = last = 1;
        len[1] = lnk[1] = 0;
    }
 
    void push (int c) {
        int cur = ++nodes, p;
        len[cur] = len[last] + 1;
        for(p = last; p && !next[p][c]; p = lnk[p]) next[p][c] = cur;
        if (!p) lnk[cur] = 1; else {
            int q = next[p][c];
            if (len[p] + 1 == len[q]) lnk[cur] = q; else {
                int clone = ++nodes;
                len[clone] = len[p] + 1;
                for(int j = 0; j < 26; j++) next[clone][j] = next[q][j];
                lnk[clone] = lnk[q];
                for(; p && next[p][c] == q; p = lnk[p]) next[p][c] = clone;
                lnk[q] = lnk[cur] = clone;
            }
        }
        last = cur;
    }
 
    void grundy_precalc () {
        for(i = 1; i <= nodes; i++) srt[i] = make_pair(len[i], i);
        sort(srt + 1, srt + nodes + 1);
        for(i = 1; i <= nodes; i++) {
            int k = srt[nodes - i + 1].second;
            dp[k] = 1;
            for(j = 0; j < 30; j++) was[j] = 0;
            for(j = 0; j < 26; j++) if (next[k][j]) was[grundy[next[k][j]]] = true;
            for(j = 0; j < 30; j++) if (!was[j]) {
                grundy[k] = j;
                break;
            }
        }        
    }    
 
    void substr_precalc () {
        for(i = 1; i <= nodes; i++) srt[i] = make_pair(len[i], i);
        sort(srt + 1, srt + nodes + 1);
        for(i = 1; i <= nodes; i++) {
            int k = srt[nodes - i + 1].second;
            dp[k] = 1;
            for(j = 0; j < 26; j++) if (next[k][j]) dp[k] += dp[next[k][j]];
        }
        ways[1] = 1;
        for(i = 1; i <= nodes; i++) for(j = 0; j < 26; j++) if (next[srt[i].second][j]) ways[next[srt[i].second][j]] += ways[srt[i].second];
        for(i = 1; i <= nodes; i++) grundy_sum[grundy[i]] += ways[i];
    }
 
    void dp_recalc (int bad_value) {
        for(i = 1; i <= nodes; i++) srt[i] = make_pair(len[i], i);
        sort(srt + 1, srt + nodes + 1);
        for(i = 1; i <= nodes; i++) {
            int k = srt[nodes - i + 1].second;
            dp[k] = grundy[k] != bad_value;
            for(j = 0; j < 26; j++) if (next[k][j]) dp[k] += dp[next[k][j]];
        }
    }
 
} sfa1, sfa2;
 
int main (int argc, char * const argv[]) {
//    freopen("input.txt", "r", stdin);
    scanf("%d %d %lld\n", &n, &m, &k);
 
    sfa1.init();
    sfa2.init();
 
    for(i = 0; i < n; i++) {
        a[i] = getchar();
        while (a[i] < 'a' || a[i] > 'z') a[i] = getchar();
        sfa1.push(a[i] - 'a');
    }
    for(i = 0; i < m; i++) {
        b[i] = getchar();
        while (b[i] < 'a' || b[i] > 'z') b[i] = getchar();
        sfa2.push(b[i] - 'a');
    }
 
    sfa1.grundy_precalc();
    for(i = 1; i <= sfa2.nodes; i++) was[i] = false;
    sfa2.grundy_precalc();
 
    sfa2.substr_precalc();    
 
    for(i = 1; i <= sfa1.nodes; i++) srt[i] = make_pair(sfa1.len[i], i);
    sort(srt + 1, srt + sfa1.nodes + 1);
    for(i = 1; i <= sfa1.nodes; i++) {
        kk = srt[sfa1.nodes - i + 1].second;
        sfa1.dp[kk] = sfa2.dp[1] - sfa2.grundy_sum[sfa1.grundy[kk]];
        for(j = 0; j < 26; j++) if (sfa1.next[kk][j]) {
            sfa1.dp[kk] += sfa1.dp[sfa1.next[kk][j]];
            if (sfa1.dp[kk] > limit) sfa1.dp[kk] = limit;
        }
    }        
 
    if (k > sfa1.dp[1]) {
        puts("no solution");
        return 0;
    }
 
    cur = 1;
    while (k > 0) {
        if (k <= sfa2.dp[1] - sfa2.grundy_sum[sfa1.grundy[cur]]) break; else k -= sfa2.dp[1] - sfa2.grundy_sum[sfa1.grundy[cur]];
        for(j = 0; j < 26; j++) if (k > sfa1.dp[sfa1.next[cur][j]]) k -= sfa1.dp[sfa1.next[cur][j]]; else {
            putchar('a' + j);
            cur = sfa1.next[cur][j];
            break;
        }
    }
    puts("");    
 
    sfa2.dp_recalc(bad_value = sfa1.grundy[cur]);
    cur = 1;
    while (k > 0) {
        if (sfa2.grundy[cur] != bad_value) {
            --k;
            if (k == 0) break;
        }
        for(j = 0; j < 26; j++) if (k > sfa2.dp[sfa2.next[cur][j]]) k -= sfa2.dp[sfa2.next[cur][j]]; else {
            putchar('a' + j);
            cur = sfa2.next[cur][j];
            break;
        }
    }
    puts("");
    return 0;
}

Java

import java.io.*;
import java.util.*;

public class Solution {

  static final int maxn = 300000;
  static final long limit = 1000000000000000000l;

  static boolean[] was = new boolean[30];
  static long[] srt;

  static class Sfa {

    long[] dp;
    long[] grundySum;
    long[] ways;

    int[][] next;
    int[] len;
    int[] lnk;
    int[] grundy;

    int nodes, last;

    Sfa(int n) {
      dp = new long[maxn * 2 + 3];
      grundySum = new long[30];
      ways = new long[maxn * 2 + 3];

      next = new int[26][maxn * 2 + 3];
      len = new int[maxn * 2 + 3];
      lnk = new int[maxn * 2 + 3];
      grundy = new int[maxn * 2 + 3];

      nodes = last = 1;
      len[1] = lnk[1] = 0;
    }

    void push(int c) {
      int cur = ++nodes, p;
      len[cur] = len[last] + 1;
      for (p = last; (p > 0) && (next[c][p] == 0); p = lnk[p]) {
        next[c][p] = cur;
      }
      if (p == 0) {
        lnk[cur] = 1;
      } else {
        int q = next[c][p];
        if (len[p] + 1 == len[q]) {
          lnk[cur] = q;
        } else {
          int clone = ++nodes;
          len[clone] = len[p] + 1;
          for (int j = 0; j < 26; j++) {
            next[j][clone] = next[j][q];
          }
          lnk[clone] = lnk[q];
          for (; (p > 0) && next[c][p] == q; p = lnk[p]) {
            next[c][p] = clone;
          }
          lnk[q] = lnk[cur] = clone;
        }
      }
      last = cur;
    }

    void grundyPrecalc() {
      for (int i = 1; i <= nodes; i++) {
        srt[i] = ((long)len[i]  << 32l) | i;
      }
      Arrays.sort(srt, 1, nodes + 1);
      for (int i = 1; i <= nodes; i++) {
        int k = (int)(srt[nodes - i + 1] & 0xffffffffL);
        dp[k] = 1;
        Arrays.fill(was, false);
        for (int j = 0; j < 26; j++) {
          if (next[j][k] > 0) {
            was[grundy[next[j][k]]] = true;
          }
        }
        for (int j = 0; j < 30; j++) {
          if (!was[j]) {
            grundy[k] = j;
            break;
          }
        }
      }
    }

    void substrPrecalc() {
      for (int i = 1; i <= nodes; i++) {
        srt[i] = ((long)len[i]  << 32l) | i;
      }
      Arrays.sort(srt, 1, nodes + 1);
      for (int i = 1; i <= nodes; i++) {
        int k = (int)(srt[nodes - i + 1] & 0xffffffffL);
        dp[k] = 1;
        for (int j = 0; j < 26; j++) {
          if (next[j][k] > 0) {
            dp[k] += dp[next[j][k]];
          }
        }
      }
      ways[1] = 1;
      for (int i = 1; i <= nodes; i++) {
        int k = (int)(srt[i] & 0xffffffffL);
        for (int j = 0; j < 26; j++) {
          if (next[j][k] > 0) {
            ways[next[j][k]] += ways[k];
          }
        }
      }
      for (int i = 1; i <= nodes; i++) {
        grundySum[grundy[i]] += ways[i];
      }
    }

    void dpRecalc(int badValue) {
      for (int i = 1; i <= nodes; i++) {
        srt[i] = ((long)len[i]  << 32l) | i;
      }
      Arrays.sort(srt, 1, nodes + 1);
      for (int i = 1; i <= nodes; i++) {
        int k = (int)(srt[nodes - i + 1] & 0xffffffffL);
        dp[k] = grundy[k] != badValue ? 1 : 0;
        for (int j = 0; j < 26; j++) {
          if (next[j][k] > 0) {
            dp[k] += dp[next[j][k]];
          }
        }
      }
    }
  }

  public static void main(String[] args) throws IOException {
    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    BufferedWriter bw = new BufferedWriter(new FileWriter(System.getenv("OUTPUT_PATH")));

    StringTokenizer st = new StringTokenizer(br.readLine());
    int n = Integer.parseInt(st.nextToken());
    int m = Integer.parseInt(st.nextToken());
    long k = Long.parseLong(st.nextToken());

    srt = new long[maxn * 2 + 3];

    Sfa sfa1 = new Sfa(n);

    char[] a = br.readLine().toCharArray();
    for (int i = 0; i < n; i++) {
      sfa1.push(a[i] - 'a');
    }

    Sfa sfa2 = new Sfa(n);

    char[] b = br.readLine().toCharArray();
    for (int i = 0; i < m; i++) {
      sfa2.push(b[i] - 'a');
    }

    sfa1.grundyPrecalc();
    for (int i = 1; i <= (sfa2.nodes > 29 ? 29 : sfa2.nodes); i++) {
      was[i] = false;
    }

    sfa2.grundyPrecalc();
    sfa2.substrPrecalc();

    for (int i = 1; i <= sfa1.nodes; i++) {
      srt[i] = ((long)sfa1.len[i]  << 32l) | i;
    }
    Arrays.sort(srt, 1, sfa1.nodes + 1);
    for (int i = 1; i <= sfa1.nodes; i++) {
      int kk = (int)(srt[sfa1.nodes - i + 1] & 0xffffffffL);
      sfa1.dp[kk] = sfa2.dp[1] - sfa2.grundySum[sfa1.grundy[kk]];
      for (int j = 0; j < 26; j++) {
        if (sfa1.next[j][kk] > 0) {
          sfa1.dp[kk] += sfa1.dp[sfa1.next[j][kk]];
          if (sfa1.dp[kk] > limit) {
            sfa1.dp[kk] = limit;
          }
        }
      }
    }

    if (k > sfa1.dp[1]) {
      bw.write("no solution");
      bw.newLine();

      bw.close();
      br.close();
      return;
    }
    int cur = 1;
    while (k > 0) {
      if (k <= sfa2.dp[1] - sfa2.grundySum[sfa1.grundy[cur]]) {
        break;
      } else {
        k -= sfa2.dp[1] - sfa2.grundySum[sfa1.grundy[cur]];
      }
      for (int j = 0; j < 26; j++)
        if (k > sfa1.dp[sfa1.next[j][cur]])
          k -= sfa1.dp[sfa1.next[j][cur]];
        else {
          bw.write('a' + j);
          cur = sfa1.next[j][cur];
          break;
        }
    }
    bw.newLine();

    int badValue = sfa1.grundy[cur];
    sfa2.dpRecalc(badValue);
    cur = 1;
    while (k > 0) {
      if (sfa2.grundy[cur] != badValue) {
        --k;
        if (k == 0) {
          break;
        }
      }
      for (int j = 0; j < 26; j++) {
        if (k > sfa2.dp[sfa2.next[j][cur]]) {
          k -= sfa2.dp[sfa2.next[j][cur]];
        } else {
          bw.write('a' + j);
          cur = sfa2.next[j][cur];
          break;
        }
      }
    }

    bw.newLine();

    bw.close();
    br.close();
  }
}

Note: This problem (Two Strings Game) is generated by HackerRank but the solution is provided by CodingBroz. This tutorial is only for Educational and Learning purpose.

Leave a Comment

Your email address will not be published. Required fields are marked *