ISIJ 2018玛雅文字

ISIJ 2018 玛雅文字(Training Round D5T1)

题目名称:玛雅文字

**文件名:**mayan.in / mayan.out

题目描述

解读玛雅文字向来不简单,因为单词中的字母顺序可以是任意排列的。今天,科研团队找到了你来解决一个简化过的问题——在给定的一段玛雅文字 S 中,求出给定的单词 T 出现了几次,并保证 S 和 T 均由大小写字母构成。

限制

1s 32M

1≤|T|≤ 3000,|T|≤|S|≤ 3,000,000

输入格式

第一行,两个整数,表示 |T| 和 |S|

第二行,一个字符串 T

第三行,一个字符串 S

输出格式

一个整数,表示出现的次数

输入样例

4 11

cAda

AbrAcadAbRa

输出样例

2

样例解释

子串 Acad 和 cadA 均是 cAda 的排列,因此一共出现了 2 次。


分析

不明白为什么会有人想到kmp,不是说好了与排列顺序无关。。。。
明显是统计相同序列长的字符串看每个字母出现次数是否相同。如果相同就ans++;本来想着hash一下,结论是完全没必要,直接暴力枚举即可。用52(104)个桶统计字母数,每次向右移动一位,维护模串长度不变,再暴力判定。时间复杂度为O(52*n)。

有复杂度更优的O(n)算法,这里不提了,反正已经做出来了,懒得写 ~~

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
char t[3100],s[3000100];
int a[26][2],b[26][2];
int lt,ls;
bool check(){
    for(int i=0;i<2;i++)
        for(int j=0;j<26;j++)
            if(a[j][i]!=b[j][i]) return 0;
    return 1;
}
int main(){
    freopen("mayan.in","r",stdin);
    freopen("mayan.out","w",stdout);
    cin>>lt>>ls;
    scanf("%s",t+1);scanf("%s",s+1);
    memset(a,0,sizeof(a));
    memset(b,0,sizeof(b));
    for(int i=1;i<=lt;i++){
        if(t[i]>='a'&&t[i]<='z') a[t[i]-'a'][0]++;
        else a[t[i]-'A'][1]++;
    }
    for(int j=1;j<=lt;j++){
        if(s[j]>='a'&&s[j]<='z') b[s[j]-'a'][0]++;
        else b[s[j]-'A'][1]++;
    }

    int i=1,j=lt,ans=0;
    if(check())ans++;
    while(j<ls){
        if(s[i]>='a'&&s[i]<='z') b[s[i]-'a'][0]--;
        else b[s[i]-'A'][1]--;
        i++,j++;
        if(s[j]>='a'&&s[j]<='z') b[s[j]-'a'][0]++;
        else b[s[j]-'A'][1]++;
        if(check())ans++;
    }
    cout<<ans<<endl;
}

猜你喜欢

转载自blog.csdn.net/xyc1719/article/details/81745291