题目描述
这是代码源5月21日的div2每日一题
Gene - 题目 - Daimayuan Online Judge
题目描述高中生物中提到,酶切位点 是基因序列上一段特定的碱基序列,而 限制性核酸内切酶 能够识别出这个序列并在对应的切割位置将基因序列切成两段。现有一种名为 EcoRIEcoRI 的限制酶,其识别序列为 GAATTC,切割位置在 G 和 A 之间。(如下图所示,本题只考虑 5'->3' 单链) 给出一段长度为 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;
}