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;
}