玛雅文字
**文件名:**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 次。
题解
维护 |S| 中所有长度为 |T| 的区间里,每种字母的出现次数,维护这与实际次数一致的字母个数,每次修改至多 2 种字母,因此可以线性扫描计数。
#include <bits/stdc++.h>
using namespace std;
template <typename T> void read(T &t) {char ch=getchar(); int f=1; t=0;while ('0'>ch||ch>'9') { if (ch=='-') f=-1; ch=getchar(); }do { (t*=10)+=ch-'0'; ch=getchar(); } while ('0'<=ch&&ch<='9'); t*=f;
}
typedef long long ll;
const int maxn=(3e6)+10;
int n,m,c1[60],c2[60],cnt,ans;
char s1[maxn],s2[maxn];
int f(char ch) {if ('a'<=ch&&ch<='z') return ch-'a'+1;return ch-'A'+27;
}
int main() {read(n); read(m);scanf("%s %s",s1+1,s2+1);for (int i=1;i<=n;i++)c1[f(s1[i])]++;for (int i=1;i<=n;i++)c2[f(s2[i])]++;for (int i=1;i<=52;i++)if (c1[i]==c2[i]) cnt++;if (cnt==52) ans++;for (int i=n+1;i<=m;i++) {int tmp=c2[f(s2[i])];c2[f(s2[i])]++;if (tmp==c1[f(s2[i])]) cnt--;else if (c2[f(s2[i])]==c1[f(s2[i])]) cnt++;tmp=c2[f(s2[i-n])];c2[f(s2[i-n])]--;if (tmp==c1[f(s2[i-n])]) cnt--;else if (c2[f(s2[i-n])]==c1[f(s2[i-n])]) cnt++;if (cnt==52) ans++;}printf("%d\n",ans);return 0;
}