代码源:928、Gene

128 阅读3分钟

logo.png

题目描述

这是代码源5月21日的div2每日一题

Gene - 题目 - Daimayuan Online Judge

题目描述高中生物中提到,酶切位点 是基因序列上一段特定的碱基序列,而 限制性核酸内切酶 能够识别出这个序列并在对应的切割位置将基因序列切成两段。现有一种名为 EcoRIEcoRI 的限制酶,其识别序列为 GAATTC,切割位置在 G 和 A 之间。(如下图所示,本题只考虑 5'->3' 单链) ecor1.png 给出一段长度为 n 的基因序列(仅由 A/T/G/C 组成的字符串),请你判断使用 EcoRI 在理想条件下能将此序列切成几个部分,并输出每个切割位置 左侧 碱基的下标。

定义该基因序列的下标从左到右分别为 1,2,3,…,n。

输入格式

第 1 行一个正整数 n 表示基因序列长度。

第 2 行一个长度为 n 的字符串表示基因序列,保证只出现 A/T/G/C 四种字符。

输出格式

第 1 行输出一个正整数 x,表示 EcoRI 在理想条件下能将给出序列切成 x 个部分。

第 2 行从小到大输出 x−1 个正整数,表示每个切割位置 左侧 碱基的下标。

样例输入

15
GATCGGAATTCTTCA

样例输出

2
6

样例说明

显然,对于此样例,容易找到 EcoRI 的识别序列和切割位点:GATCGG↓AATTCTTCA。

所以,可以将原基因序列切割成 2 部分,切割位置左侧碱基 G 的下标为 6。

数据范围

6≤n≤10^7

问题解析

这题要我们做的就是在它给的字符串里去找“GAATTC”这个字符串,把这个字符串的第一个字母A的下标输出即可,那么我们就用能快速找到对应字符串的做法就可以了,可以是kmp,字符串哈希,偷懒点直接用STL自带的find()函数也可以。

一、find()函数

s.find(string,int),find函数的两个参数,前面是我们要找的字符串,后面的数字是下标,是希望我们从s的哪一个下标开始搜索字符串,如果找到了就会返回这个字符串第一个字符的下标,比如样例这里用find找就会返回5,我们再++就是我们要的A字符下标了。

如果字符串s中有多个我们要找的“GAATTC”,find函数会返回找到的第一个的下标,此时只要我们改变find函数的第二个参数,让他从找到的字符串后面开始找起就行。如果找不到,find函数返回的下标会大于s的长度,我们可以通过判断这个来停止搜索。

AC代码

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<math.h>
#include<set>
#include<numeric>
#include<string>
#include<string.h>
#include<iterator>
#include<map>
#include<unordered_map>
#include<stack>
#include<list>
#include<queue>
#include<iomanip>

#define endl '\n'
#define int ll
typedef long long ll;
typedef pair<ll, ll>PII;
const int N = 1e6 + 50;

signed main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    int n;
    string s;
    cin >> n >> s;
    vector<int>v;
    int ans = 0;

    while (s.find("GAATTC", ans) < n)
    {
        ans = s.find("GAATTC", ans);
        ans++;
        v.push_back(ans);
    }
    cout << v.size() + 1 << endl;
    for (auto i : v)cout << i << " ";
    
    return 0;
}

二、字符串哈希

AC代码

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<math.h>
#include<set>
#include<numeric>
#include<string>
#include<string.h>
#include<iterator>
#include<map>
#include<unordered_map>
#include<stack>
#include<list>
#include<queue>
#include<iomanip>

#define endl '\n'
#define int ll
typedef long long ll; typedef unsigned long long ull;
typedef pair<ll, ll>PII;
const int N = 1e6 + 50;
int n, m, p = 99971, base = 13331;

ull get_hash(vector<ull>& v, int l, int r, vector<ull>& bpow)
{
    ull t = v[l - 1] * bpow[r - l + 1];
    return (v[r] - t + p);
}

signed main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    int n;
    string s;
    cin >> n >> s;
    vector<ull>v(n + 1), bpow(n + 1, 1);
    ull res = 0;
    for (int i = 1; i <= n; i++)
    {
        res = (res * base + s[i - 1]);
        v[i] = res;
        bpow[i] = bpow[i - 1] * base;
    }
    string str = "GAATTC";
    res = 0;
    for (int i = 1; i <= 6; i++)
    {
        res = (res * base + str[i - 1]);
    }
    res += p;
    vector<int>cnt;
    for (int i = 1; i <= n; i++)
    {
        if (s[i - 1] == 'G')
        {
            ull x = get_hash(v, i, i + 5, bpow);
            if (x == res)
            {
                cnt.push_back(i);
            }
        }
    }
    cout << cnt.size() + 1 << endl;
    for (auto i : cnt)cout << i << endl;
    
    return 0;
}