Problem:
共通部分文字列

問題

2 個の文字列が与えられたとき, 両方の文字列に含まれる文字列のうち最も長いものを探し, その長さを答えるプログラムを作成せよ.

ここで, 文字列 s が文字列 t に含まれるとは, t の中に s が連続して現れることをいう. 空文字列, すなわち長さ 0 の文字列は, どんな文字列にも含まれる. 例えば, 文字列 ABRACADABRA には次の文字列が含まれる: ABRA, RAC, D, ACADABRA, ABRACADABRA,空文字列など. 一方, 文字列 ABRACADABRA には次の文字列は含まれない: ABRC, RAA,BA, K など.

例

例 1: 文字列として ABRACADABRA と ECADADABRBCRDARA が与えられた場合, 両方に含まれる文字列には CA や CADA や ADABR や空文字列などがある. そのうち最も長いのは ADABR であり, その長さは 5 である. 2 個の文字列の中に含まれる ADABR
の位置を以下に示す.

ABRACADABRA

ECADADABRBCRDARA

例 2: 文字列として UPWJCIRUCAXIIRGL と SBQNYBSBZDFNEV が与えられた場合, 両方に含まれる文字列は空文字列のみであり, その長さは 0 である.

入力

入力は複数のデータセットからなる．各データセットは以下の形式で与えられる．

入力は 2 行からなり, 1 行目に 1 個目の文字列が, 2 行目に 2 個目の文字列が与えられる. 文字列は英大文字からなり, 各々の文字列の長さは 1 以上 4000 以下である.

採点用データのうち, 配点の 30% 分については, 各々の文字列の長さは 1 以上 50以下である.

入力の終わりは EOF で示される. データセットの数は 10 を超えない．

出力

データセットごとに与えられた 2 個の文字列の両方に含まれる文字列のうち最も長いものの長さを 1 行に出力する.

入出力例

入力例

ABRACADABRA
ECADADABRBCRDARA
UPWJCIRUCAXIIRGL
SBQNYBSBZDFNEV

出力例

5
0

上記問題文と自動審判に使われるデータは、情報オリンピック日本委員会が作成し公開している問題文と採点用テストデータです。

Solution in JAVA (judge verdict: Wrong Answer)

import java.util.Scanner;

public class Main {
	static final int d = 26;
	static final int q = 255;

	public static void main(String args[]) {
		Scanner sc = new Scanner(System.in);
		String st1, st2;
		int max, sum;
		int hash1, hash2;
		int maxDigit;

		while (sc.hasNext()) {
			st1 = sc.next();
			st2 = sc.next();
			max = 0;
			hash1 = st1.charAt(0) - 'A' + 1;
			hash2 = st2.charAt(0) - 'A' + 1;
			maxDigit = 1;

			for (int i = 0; i + max < st1.length(); i++) {
				if (0 < i) {
					hash1 = hashRecreate(st1, i, max + 1, hash1, maxDigit);
				}
				if (max + 1 < st2.length()) {
					hash2 = hashInit(st2, max + 1);
				}
				for (int j = 0; j + max < st2.length(); j++) {
					if (0 < j) {
						hash2 = hashRecreate(st2, j, max + 1, hash2, maxDigit);
					}
					if (st1.charAt(i) == st2.charAt(j) && hash1 == hash2) {
						sum = f(st1, st2, i, j);
						if (max < sum) {
							for (int k = 0; k < sum - max; k++) {
								if (i + max + k + 1 < st1.length() && j + max + k + 1 < st2.length()) {
									hash1 *= d;
									hash1 += st1.charAt(i + max + k + 1) - 'A' + 1;
									hash1 %= q;
									hash2 *= d;
									hash2 += st2.charAt(j + max + k + 1) - 'A' + 1;
									hash2 %= q;
								}
								maxDigit *= d;
							}
							max = sum;
						}
					}
				}
			}
			System.out.println(max);
		}
	}

	public static int f(String st1, String st2, int index1, int index2) {
		int count = 0;

		for (int i = 0; index1 + i < st1.length() && index2 + i < st2.length(); i++) {
			if (st1.charAt(index1 + i) == st2.charAt(index2 + i)) {
				count++;
			} else {
				break;
			}
		}
		return count;
	}

	public static int hashRecreate(String st, int startIndex, int length, int hash, int maxDigit) {
		hash -= (st.charAt(startIndex - 1) - 'A' + 1) * maxDigit;
		hash *= d;
		hash += st.charAt(startIndex + length - 1) - 'A' + 1;
		hash %= q;
		if (hash < 0) {
			hash += 255;
		}

		return hash;
	}

	public static int hashInit(String st, int length) {
		int hash = st.charAt(0) - 'A' + 1;

		for (int i = 1; i < length; i++) {
			hash *= d;
			hash += st.charAt(i) - 'A' + 1;
		}
		hash %= q;
		if (hash < 0) {
			hash += 255;
		}

		return hash;
	}
}