AOJ0040

問題:Affine Cipher
アフィン暗号で暗号化された文字列を復号する問題.
F(γ) = (α・γ+β) mod 26
文字列の各文字はこの式に基づいて暗号化されている.αとβは分からない.
ただし,元の文字列には必ず"this"か"that"が入っているのでここからαとβを求め,文字列を復号する.

方針は,考えられるすべてのα,βのパターンで"this"と"that"をアフィン暗号化してテーブルを作っておく.
入力された文字列とテーブルからα,βを特定し,元の文字列に戻す.
上式の逆関数を求めるのではなく,これもテーブル化すると楽.
map便利ィ!!

#include <iostream>
#include <vector>
#include <string>
#include <sstream>
#include <map>
#define rep(i,n) for(int i=0;i<n;++i)
using namespace std;

char F(int a,int b,char y){
	y = y-'a';
	return (a*y + b)%26 + 'a';
}
int main(){
	string s1,s2;
	map<string,pair<int,int> > table;
	s1 = "this";
	s2 = "that";
	int a,b;
	for(a=0;a<26;++a)for(b=0;b<26;++b){
		if(a%13==0 || a%2==0)continue;
		string s1_,s2_;
		for(int i=0;i<4;++i)s1_ += F(a,b,s1[i]);
		for(int i=0;i<4;++i)s2_ += F(a,b,s2[i]);
		table[s1_] = pair<int,int>(a,b);
		table[s2_] = pair<int,int>(a,b);
	}
	int n;
	cin >> n;
	string tmp;
	getline(cin,tmp);
	for(int l=0;l<n;++l){
		map<char,char> trans;
		string s;
		stringstream ss;
		vector<string> vs,vst;
		int a,b;
		getline(cin,s);
		ss << s;
		while(ss >> s){
			if(s.length() == 4)
				vs.push_back(s);
			vst.push_back(s);
		}
		rep(i,vs.size()){
			if ( table.find( vs[i] ) != table.end() ){
				a = table[vs[i]].first;
				b = table[vs[i]].second;
				break;
			}
		}
		rep(i,26){
			trans[ F(a,b,i+'a') ] = i+'a';
		}
		rep(i,vst.size()){
			rep(j,vst[i].size()){
				cout << trans[vst[i][j]];
			}
			if(i==vst.size()-1)cout << endl;
			else cout << " ";
		}
	}
	return 0;
}