Singing Superstar
题意:给你一个字符串,q个查询,每次询问一个长度不大于30的字符串在所给字符串中最多不重复出现的次数
贪心统计每个询问字符串的个数即可
哈希解法
参考题解
#include<bits/stdc++.h>
#define ull unsigned long long
using namespace std;
const ull p = 131;
const int maxn = 1e5 + 9;
ull Pow[maxn] = {1};
ull Hash[maxn];
unordered_map <ull,int> cnt;
unordered_map <ull,int> last;
char s[maxn], t[35];
int n, q, m;
inline ull getsub(int l, int r)
{
return Hash[r] - Hash[l - 1] * Pow[r - l + 1];
}
void work()
{
cnt.clear();last.clear();
scanf("%s", s + 1); n = strlen(s + 1);
for(int i = 1; i <= n; ++i) Hash[i] = Hash[i-1] * p + s[i];
cin >> q;
ull a[q + 1];//存下来q个询问字符串的哈希值
for(int k = 1; k <= q; ++k)
{
scanf("%s", t + 1);m = strlen(t + 1);
ull Ha = 0;
for(int i = 1; i <= m; ++i) Ha = Ha * p + t[i];
a[k] = Ha;
cnt[Ha] = last[Ha] = 0;
// 此时的cnt[Ha]和lst[Ha]对应的值是0,并不是空的映射,不是null
// 0 和 null不是等价的
}
for(int l = 1; l <= 30; ++l)
for(int i = 1; i + l - 1 <= n; ++i)
{
ull hs = getsub(i, i + l - 1);
if(cnt.count(hs) && last[hs] <= i)
{//count判断关键字是否在map中出现
last[hs] = i + l;
cnt[hs]++;
}
}
for(int i = 1; i <= q; ++i)
printf("%d\n", cnt[a[i]]);
}
int main()
{
for(int i = 1; i <= maxn - 3; ++i) Pow[i] = Pow[i-1] * p;
int TT;cin>>TT;while(TT--)
work();
return 0;
}
字典树解法
参考题解
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 7;
int n, t, m;
int nex[maxn * 33][27], cnt;
unordered_map <int,pair<int,int> > last;
char s[maxn], pt[maxn];
void insert(char *s)// 将母串长度小于等于30的子串插入字典树,并统计不相交的数量
{
int l = strlen(s);
for (int i = 0; i < l; i++)
{
int c = 0, op;
for (int j = i; j < i + 30 && j < l; j++)
{
op = s[j] - 'a';
if (!nex[c][op]) nex[c][op] = ++cnt;
c = nex[c][op];
// 没有出现过这个字符串 或者 两个字符串相同但不相交(字符串末尾差值大于大于等于该串长度)
if(!last.count(c)) last[c] = make_pair(1, j);// 第一次出现统计为 1
else if(j - last[c].second >= j - i + 1){// 满足条件增加一个
int x = last[c].first + 1;
last[c] = make_pair(x, j);
}
}
}
}
int find(char *s)
{
int l = strlen(s), c = 0;
for (int i = 0; i < l; i++)
{
int op = s[i] - 'a';
if (!nex[c][op]) return 0;
c = nex[c][op];
}
return last[c].first;
}
void solve()
{
scanf("%d", &t);
while (t--)
{
last.clear();
scanf("%s", s);
insert(s);
scanf("%d", &n);
for (int i = 1; i <= n; i++)
{
scanf("%s", pt);
printf("%d\n", find(pt));
}
for (int i = 0; i <= cnt; i++)
{
for (int j = 0; j <= 26; j++)
nex[i][j] = 0;
}
cnt = 0;
}
}
int main()
{
solve();
return 0;
}