1. 题目
碱基
生物学家正在对n个物种进行研究。
其中第i个物种的DNA序列为s[i],其中的第j个碱基为s[i][j],碱基一定是A、T、G、C之一。
生物学家想找到这些生物中一部分生物的一些共性,他们现在关注那些至少在m个生物中出现的长度为k的连续碱基序列。准确的说,科学家关心的序列用2m元组(i1,p1,i2,p2…im,pm)表示,
满足:
1<=i1<i2<…<im<=n;
且对于所有q(0<=q<k), s[i1][p1+q]=s[i2][p2+q]=…=s[im][pm+q]。
现在给定所有生物的DNA序列,请告诉科学家有多少的2m元组是需要关注的。如果两个2m元组有任何一个位置不同,则认为是不同的元组。
【输入格式】
输入的第一行包含三个整数n、m、k,两个整数之间用一个空格分隔,意义如题目所述。
接下来n行,每行一个字符串表示一种生物的DNA序列。
DNA序列从1至n编号,每个序列中的碱基从1开始依次编号,不同的生物的DNA序列长度可能不同。
【输出格式】
输出一个整数,表示关注的元组个数。
答案可能很大,你需要输出答案除以1000000007的余数。
【样例输入】
3 2 2
ATC
TCG
ACG
【样例输出】
2
再例如:
【样例输入】
4 3 3
AAA
AAAA
AAA
AAA
【样例输出】
7
【数据规模与约定】
对于20%的数据,k<=5,所有字符串总长L满足L <=100
对于30%的数据,L<=10000
对于60%的数据,L<=30000
对于100%的数据,n<=5,m<=5,1<=k<=L<=100000
保证所有DNA序列不为空且只会包含’A’ ’G’ ’C’ ’T’四种字母
资源约定:
峰值内存消耗 < 256M
CPU消耗 < 1000ms
请严格按要求输出,不要画蛇添足地打印类似:“请您输入…” 的多余内容。
所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意:不要使用package语句。不要使用jdk1.7及以上版本的特性。
注意:主类的名字必须是:Main,否则按无效代码处理。
2. 分析
这是一道阅读题,读懂题意就简单了。
题目意思就是在n个物种里选m个,然后这m个物种呢,都有相同的长度为k的子串
然后问你有多少种子串组合方式。
例如样例2.
首先有4个物种,在4个里面挑3个
{1, 2, 3}, {1, 2, 4}, {1, 3, 4}, {2, 3, 4}
四种组合方式
然后组合方式中找子串相同的情况有多少种。
{1, 2, 3}
是两种
{1, 2, 4}
也是两种
{2, 3, 4}
也是两种
{1, 3, 4}
是一种,加起来就是七种
因为n和m比较小,所以可以枚举出所有组合。
然后再选取第一个序列,暴力枚举出所有长度为k的子串,找这些子串在后序序列中的个数,相乘就能得到答案
3. 代码
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.StringTokenizer;
public class Main {
static InputReader in = new InputReader(new BufferedInputStream(System.in));
static PrintWriter out = new PrintWriter(System.out);
static String[] jianji = new String[15];
static int[] arr = new int[15];
static boolean[] vis = new boolean[15];
static int n, m, k, sum = 0;;
static int find(String a, String b) {
// a中有多少个b子串
int k = -1;
int cnt = -1;
while (k != 0) {
k = a.indexOf(b, k) + 1;
cnt++;
}
return cnt;
}
// n个数选m个。
static void dfs(int cnt) {
if (cnt == m+1) {
String s = jianji[arr[1]];
for (int i = 0; k+i <= s.length(); i++) {
String sub = s.substring(i, k+i);
int t = 1;
for (int j = 2; j <= m; j++) {
// 看后序序列中包含了多少个s子串
t = (t * find(jianji[arr[j]], sub)) % 1000000007;
}
sum = (sum + t) % 1000000007;
}
return ;
}
// 从上一个数+1开始取
for (int q = arr[cnt-1] + 1; q <= n; q++) {
if (vis[q] == false) {
vis[q] = true;
arr[cnt] = q;
dfs(cnt+1);
vis[q] = false;
}
}
}
public static void main(String[] args) {
n = in.nextInt();
m = in.nextInt();
k = in.nextInt();
for (int i = 1; i <= n; i++) {
jianji[i] = in.readLine();
}
dfs(1);
// 枚举所有情况
out.println(sum);
out.flush();
out.close();
}
public static class InputReader {
public static BufferedReader br;
public static StringTokenizer st;
public InputReader(InputStream stream) {
br = new BufferedReader(new InputStreamReader(stream), 32768);
st = null;
}
public String next() {
while(st == null || !st.hasMoreTokens()) {
try {
st = new StringTokenizer(br.readLine());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return st.nextToken();
}
public String readLine() {
String s = null;
try {
s = br.readLine();
} catch (IOException e) {
e.printStackTrace();
}
return s;
}
public int nextInt() {
return Integer.parseInt(next());
}
public Long nextLong() {
return Long.parseLong(next());
}
public Double nextDoule() {
return Double.parseDouble(next());
}
}
}