15年国赛 密文搜索

标题:密文搜索

福尔摩斯从X星收到一份资料,全部是小写字母组成。
他的助手提供了另一份资料:许多长度为8的密码列表。
福尔摩斯发现,这些密码是被打乱后隐藏在先前那份资料中的。

请你编写一个程序,从第一份资料中搜索可能隐藏密码的位置。
要考虑密码的所有排列可能性。

数据格式:

输入第一行:一个字符串s,全部由小写字母组成,长度小于1024*1024
紧接着一行是一个整数n,表示以下有n行密码,1<=n<=1000
紧接着是n行字符串,都是小写字母组成,长度都为8

要求输出:
一个整数, 表示每行密码的所有排列在s中匹配次数的总和。

例如:
用户输入:
aaaabbbbaabbcccc
2
aaaabbbb
abcabccc

则程序应该输出:
4

算法的设计根据这样一个特性:
设,n个素数的积为:m
则,m可以唯一地分解为这些素数因子。
只要把每个字母对应一个不同的素数,包含不同字母组合的集团就可以用它们的积表示。
只要判断积是否相同,就知道是否包含了同一组字母。


import java.util.*;
public class Main
{
	static int[] prm = {2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101};
	static long[] kkey;
	static int N = 8;
	
	static void create_kkey(String mother){
		kkey = new long[mother.length()-N+1];
		
		kkey[0] = 1;
		for(int i=0; i<N; i++) kkey[0] *= prm[mother.charAt(i)-'a'];
		
		for(int i=1; i<kkey.length; i++){
			kkey[i]=kkey[i-1] / prm[mother.charAt(i-1)-'a'] * prm[mother.charAt(i+N-1)-'a'];
		}	
	}
	
	public static int find(String child)
	{
		long key = 1;
		for(int j=0; j<child.length(); j++) 
			key *= prm[child.charAt(j)-'a'];
		
		int n = 0;
		for(int i=0; i<kkey.length; i++) if(kkey[i]==key) n++;
		
		return n;
	}
	
	public static void main(String[] args)
	{
		Scanner scan = new Scanner(System.in);
		String mother = scan.nextLine();
		
		create_kkey(mother);
		
		int n = Integer.parseInt(scan.nextLine());
			
		int sum = 0;
		for(int i=0; i<n; i++){
			sum += find(scan.nextLine());
		}
		
		System.out.println(sum);				
	}
}

猜你喜欢

转载自blog.csdn.net/Baobab_Tree/article/details/90105404