Problem:
MathJax.Hub.Config({ tex2jax: { inlineMath: [["$","$"], ["\\(","\\)"]], processEscapes: true }});

アフィン暗号

簡単な暗号法の一つに、アフィン暗号というものがあります。まず、アルファベット a〜z を a = 0, b = 1, c = 2,..., x = 23, y = 24, z = 25 と 0〜25 の数字に置き換えます。そして、以下の式で、原文のアルファベットを置換します。

$F(\gamma) = (\alpha \cdot \gamma + \beta)$ mod $26$

ただし、mod 26 は 26 で割った余りを表します。例えば、$\alpha = 3, \beta = 2$ のとき、アルファベットの 'a' (=0) は、$F(0) = (3 \cdot 0 + 2)$ mod $26 = 2$ で 'c' に、アルファベットの 'n' (=13) は $F(13) = (3 \cdot 13 + 2)$ mod $26 = 15$ で 'p' に置換されます。
このとき、$\gamma$ に対する $F(\gamma)$ が必ず 1 対 1 で対応付けられるように、$\alpha$ と $\beta$ は慎重に選ばれているものとします（$\alpha$ と 26 が互いに素であることが条件）。$\alpha = 4, \beta = 7$ のときのように、$F('a') = 7, F('n') = 7$ と、'a' も 'n' も同じ 'h' に置換されるようなことはありません。また、アルファベット以外の文字は置換されません。

暗号化された文字列を元の文章に復号したものを出力するプログラムを作成してください。元の文章には、キーワードとして

that
this

のいずれかが必ず含まれているものとします。

Input

複数のデータセットが与えられます。１行目にデータセット数 $n$ ($n \leq 30$) が与えられます。続いて $n$ 行のデータが与えられます。各データセットに英小文字と空白からなる 256 文字以内の暗号化された文章が１行に与えられます。

Output

各データセットに対して、復号した元の文章を１行に出力して下さい。

Sample Input

1
y eazqyp pnop pngtg ye obmpngt xmybp mr lygw

Output for the Sample Input

i submit that there is another point of view

Solution in JAVA (judge verdict: Accepted)

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;


public class Main {
	private	static	BufferedReader	br = null;

	static {
		br   = new BufferedReader(new InputStreamReader(System.in));
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		String	strStdin = null;
		int		nNum     = 0;
		boolean	bLoop    = true;

		while((strStdin = parseStdin()) != null) {
			nNum = Integer.parseInt(strStdin);
			for (int n = 0; n < nNum; n++) {
				if((strStdin = parseStdin()) != null) {
					bLoop = true;
					for (int nA = 1; nA < 26 && bLoop; nA += 2) {
						if (nA == 13) {
							continue;
						}
						for (int nB = 0; nB < 26 && bLoop; nB++) {
							if (strStdin.contains(encode("this", nA, nB)) || strStdin.contains(encode("that", nA, nB))) {
								System.out.println(decode(strStdin, nA, nB));
								bLoop = false;
							}
						}
					}
				}
			}
		}
	}

	private static String encode(String strNum, int nA, int nB) {
		String	strTmp = "";
		int		nTmp   = 0;

		for (char c : strNum.toCharArray()) {
			// Ck = APk + K (mod M)
			if (Character.isLowerCase(c)) {
				nTmp = (nA * (c - 'a') + nB) % 26 + 'a';
				c    = (char)nTmp;
			}
			strTmp += c;
		}

		return strTmp;
	}

	private static String decode(String strNum, int nA, int nB) {
		String	strTmp = "";
		int		nInvA  = inverse(nA);
		int		nTmp   = 0;

		for (char c : strNum.toCharArray()) {
			// Pk = A-1(Ck - K) (mod M)
			if (Character.isLowerCase(c)) {
				nTmp = (nInvA * (c - 'a' - nB + 26)) % 26 + 'a';
				c    = (char)nTmp;
			}
			strTmp += c;
		}

		return strTmp;
	}

	private static int inverse(int nA) {
		int	nInvA  = 0;

		switch (nA) {
        case 1:
        	nInvA = 1;
        	break;
        case 3:
        	nInvA = 9;
        	break;
        case 5:
        	nInvA = 21;
        	break;
        case 7:
        	nInvA = 15;
        	break;
        case 9:
        	nInvA = 3;
        	break;
        case 11:
        	nInvA = 19;
        	break;
        case 15:
        	nInvA = 7;
        	break;
        case 17:
        	nInvA = 23;
        	break;
        case 19:
        	nInvA = 11;
        	break;
        case 21:
        	nInvA = 5;
        	break;
        case 23:
        	nInvA = 17;
        	break;
        case 25:
        	nInvA = 25;
        	break;
		}

		return nInvA;
	}

	private static String parseStdin() {
		String	strNum = null;

		try {
			String line = br.readLine();
			if (line != null) {
				if (!line.isEmpty()) {
					strNum = line;
				}
			}
		}
		catch (IOException e) {}

		return strNum;
	}
}