第七届 蓝桥杯 java c组 第六题


碱基

生物学家正在对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,否则按无效代码处理。
 

 

package The_Seven;

import ErArr.ErArr;

import java.awt.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Scanner;
import java.util.Set;

public class Six {
    public static int n;//生物个数
    public static int m;//最少在多少个生物中出现
    public static int k;//长度为k
    public static int css;
    public static void main(String[] args) {
        //碱基
        //思路:求出 所有生物中所有符合目标长度的串 都在那个生物中出现过 出现过几次
        //比如
        /*
            ATC
            TCG
            ACG
            AT串 出现在第一个生物 出现了一次
            TC串 出现在第一个生物中 1次  出现在第二个生物中 1次
            .....
            需要组合 的情况
            例如
            AAA
            AAAA
            AAA
            AAA
            其中AAA串 {(第一行,1次),(第二行,2次),(第三行,1次),(第四行,1次)}
            共可以组合出7种 {(1),(2,3),(4),(5)}用数字来表示
            可组合为
            124
            125
            134
            135
            245
            345
            145

            根据条件至少在几个生物中出现 找符合条件的串的数量即可


         */

        //求出 每个目标长度的串:{他出现的位置 有多个}
        Scanner sr = new Scanner(System.in);
        n = sr.nextInt();
        m = sr.nextInt();
        k = sr.nextInt();
        String []arr = new String[n];//n个生物的dna序列
        for (int i = 0; i < arr.length; i++) {
            arr[i] = sr.next();
        }
        //count 中 装生物 位置的集合
        HashMap<String,ArrayList<Point>> count = new HashMap<String,ArrayList<Point>>();
        //遍历DNA
        for (int i = 0; i < arr.length; i++) {
            //遍历当前生物的DNA 并截取成目标长度的串
            for (int j = 0; j <= arr[i].length()-k; j++) {
                String s = arr[i].substring(j,j+k);
                //当前串是否已经存在于集合中 (不分生物)
                if (!count.containsKey(s)){
                    ArrayList<Point> zc = new ArrayList<Point>();
                    Point p = new Point(i,1);//分别代表:所在的生物的索引 , 出现的次数
                    zc.add(p);
                    count.put(s,zc);
                }else{
                    //这里是 判断 当前串 是不是在当前生物中 已经存在过了 如果是就给当前生物的当前串的数量+1即可
                    boolean sign1 = false;
                    for (int l = 0; l < count.get(s).size(); l++) {
                        if (count.get(s).get(l).x==i){
                            count.get(s).get(l).y++;
                            sign1 = true;
                            break;
                        }
                    }
                    if (!sign1){
                        Point p = new Point(i,1);
                        count.get(s).add(p);
                    }
                }
            }
        }
        //遍历所有串
        Set<String> key = count.keySet();
        for (String k : key){
            //如果当前串 在达到或超过 “至少在m个生物中出现的长度” 时需要进行组合
            //例如 在第一个生物出现1次 在第二个生物出现2次 在第三个生物出现1次 条件是最少在3个生物中出现 那么就会有两种情况
            if (count.get(k).size()>=m){
                int [][]z = new int[count.get(k).size()][];
                for (int i = 0; i < z.length; i++) {
                    z[i] = new int[count.get(k).get(i).y];
                }
//                ErArr.Int(z);
                zh(0,m-1,z);
//                System.out.println(css);
//                System.out.println("-------------");
            }
        }
        System.out.println(css);
    }
    //start:当前数可以是的行    index:当前行的第几个
    public static void zh(int start,int index,int [][]z){
        if (index<0){
            css++;
            return;
        }
//        System.out.println("index "+(3-index)+" 范围: "+start+" 行到: "+(z.length-index)+" 行"+"当前组成: "+cs);//debug
        for (int i = start; i < z.length-index; i++) {
            for (int j = 0; j < z[i].length; j++) {
                zh(i+1,index-1,z);
            }
        }
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值