简单 hash 入门题目

题目描述

NOIP 复赛之前,HSD 桑进行了一项研究,发现人某条染色体上的一段 DNA 序列中连续的 kkk 个碱基组成的碱基序列与做题的 AC 率有关!于是他想研究一下这种关系。
现在给出一段 DNA 序列,请帮他求出这段 DNA 序列中所有连续 kkk 个碱基形成的碱基序列中,出现最多的一种的出现次数。

输入格式

两行,第一行为一段 DNA 序列,保证 DNA 序列合法,即只含有 A, G, C, T 四种碱基;
第二行为一个正整数 kkk,意义与题目描述相同。

输出格式

一行,一个正整数,为题目描述中所求答案。

样例
样例输入 1
AAAAA
1
样例输出 1
5
样例解释 1

对于这段 DNA 序列,连续的 111 个碱基组成的碱基序列只有 A,共出现 555 次,所以答案为 555。

样例输入 2
ACTCACTC
4
样例输出 2
2
样例解释 2

对于这段 DNA 序列,连续的 444 个碱基组成的碱基序列为:ACTC, CTCA, TCACCACT。其中 ACTC 出现 222 次,其余均出现 111 次,所以出现最多的次数为 222,即为答案。

数据范围与提示

记 DNA 序列长度为 nnn。
本题共 101010 组数据,只有输出与标准输出一致才可以获得该测试点的分数。

下面给出每组数据的范围和满足性质情况:

测试点编号nnnkkk其他
111=105=10 ^5=105​​=1=1=1满足性质
2,32,32,3≤5×105\le 5 \times 10 ^55×105​​=1=1=1-
444≤5×105\le 5 \times 10 ^55×105​​≤10\le 1010满足性质
5,6,7,85,6,7,85,6,7,8≤106\le 10 ^6106​​≤10\le 1010-
9,109,109,10=5×106=5 \times 10 ^6=5×106​​=10=10=10-

性质:给出的 DNA 碱基序列中每个碱基均相同。
对于所有数据均保证 k≤nk\le nkn

 

思路分析 : hash 拉链即可解决

代码示例:

using namespace std;
#define ll unsigned long long
const ll maxn = 5e6+5;
const ll mm = 200007;

char s[maxn];
ll k, len;
ll p = 19873;
ll hash_[maxn], pp[maxn];

void init_hash() {
    hash_[0] = 0; pp[0] = 1;
    for(ll i = 1; i <= len; i++) {
        hash_[i] = hash_[i-1]*p + (s[i]-'a'); 
        pp[i] = pp[i-1]*p;
    }  
}
struct node
{
    ll x;
    ll cnt = 0;
    int next; //!!!
}arr[maxn];
int head[mm+50];
ll tot = 1;

ll _max(ll a, ll b){
    return a>b?a:b;
}
void solve() {
    ll ans = 1;
    memset(head, -1, sizeof(head));    
    for(ll i = k; i <= len; i++){
        ll num = hash_[i]-hash_[i-k]*pp[k];
        ll num2 = num%mm;
        int f = head[num2];
        int sign = 0;
        while(f != -1) {
            if (arr[f].x == num) {
                arr[f].cnt++;
                ans = _max(ans, arr[f].cnt);
                sign = 1;
                break;
            }
            f = arr[f].next;
        }
        if (sign) continue;
        arr[tot].x = num;
        arr[tot].cnt = 1;
        arr[tot].next = head[num2];
        head[num2] = tot++;
    }
    printf("%lld\n", ans);
}

int main() {
    
    scanf("%s", s+1);
    len = strlen(s+1);
    scanf("%llu", &k);
    init_hash();
    solve();
    return 0;
}

 

转载于:https://www.cnblogs.com/ccut-ry/p/9648246.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值