题目训练网址(密码hpuacm): https://cn.vjudge.net/contest/247842
Crazy Search
给定一个字符串,其中含有不同的字母数量为m,现在求这个字符串中有多少个长度为n且长的互不相同的字符子串
举个例子, n=3, m=4 ,字符串 "daababac". 长度为3的不同的子串分别是: "daa"; "aab"; "aba"; "bab"; "bac". 因此, 答案是5.
Input
第一行是两个整数n,m,,一个空格隔开。 接下来一行是我们要解决的字符串.( 你可以认为字符串的长度不会超过一千六百万。)Orz我读错题了,并不是字符串长度不超过1600万,是合理hash之后的hash的值不超过1600万。Orz原谅我
Output
程序应该输出一个整数,对应于给定文本中所找到的大小为n的不同子字符串的数量。
输入数据
3 4
daababac
输出数据
5
//#include <bits/stdc++.h>
#include <stdio.h>
#include <string.h>
using namespace std;
const int MAXN = (int) 16e6+7;
char str[MAXN];
bool vis[MAXN];
int ascii[256];
int main()
{
int n, nc;
while( ~scanf("%d%d", &n, &nc) )
{
memset(str, 0, sizeof(str));
memset(ascii, 0, sizeof(ascii));
memset(vis, 0, sizeof(vis));
scanf("%s", str);
int len = strlen(str);
for( int i=0; i<len; i++ )
ascii[str[i]] = 1; // 标记字母是否出现过
int cnt = 0;
for( int i=0; i<256; i++ )
if( ascii[i] )
ascii[i] = cnt++; // 对出现过的字母赋值
int sum = 0; //统计第一个长度为n的substring的HashValue存为sum
for( int i=0; i<n; i++ )
{
sum = sum * nc + ascii[str[i]];
}
int ans = 0; // answer
if( !vis[sum] )
{
vis[sum] = 1;
ans++;
}
int pow = 1;
for( int i=0; i<n-1; i++ )
pow *= nc; // base 1-n
for( int i=n; i<len; i++ )
{
sum -= ascii[str[i-n]] * pow;
sum *= nc;
sum += ascii[str[i]];
if( !vis[sum] ) // 经过运算,如果sun的值没有改变则两个子串相同
{
ans ++;
vis[sum] = 1;
}
}
printf("%d\n", ans);
}
return 0;
}
Oulipo
求模式串在待匹配串的出现次数。
Input
第一行是一个数字T,表明测试数据组数。
之后每组数据都有两行:第一行为模式串,长度不大于10000;第二行为待匹配串,长度不大于1000000。所有字符串只由大写字母组成。
Output
每组数据输出一行结果。
Sample Input
4
ABCD
ABCD
ABA
ABABABA
CDCDCDC
CDC
KMP
NAIVE
Sample Output
1
3
0
0
#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ULL;
const int MAXN = (int) 1e6 + 7;
char s1[MAXN];
char s2[MAXN];
ULL hash_val[MAXN];
ULL power[MAXN];
int main()
{
int t;
scanf("%d", &t);
power[0] = 1;
for( int i=1; i<MAXN; i++ )
power[i] = power[i-1] * 31;
while( t-- )
{
memset(hash_val, 0, sizeof(hash_val));
scanf("%s", s1+1);
scanf("%s", s2+1);
ULL base = 31;
int len1 = strlen(s1+1);
int len2 = strlen(s2+1);
ULL val = 0;
for( int i=1; i<=len1; i++ )
{
val = val * base + s1[i];
}
hash_val[0] = 0;
for( int i=1; i<=len2; i++ )
{
hash_val[i] = hash_val[i-1] * base + s2[i];
}
int ans = 0;
for( int i=len1; i<=len2; i++ )
{
if( hash_val[i] - hash_val[i-len1] * power[len1] == val )
ans ++;
}
printf("%d\n", ans);
}
return 0;
}