标签:因此 front char* cstring 复杂度 为我 check log 元素
要使得包含单词最多,那么就需将文章中所有在单词表中出现过的单词全部统计。
而一个字符一个字符的比对复杂度过高,因此我们需要求出单词表与文章的字符串哈希,这样我们就可以\(O(1)\)比较了。而哈希之后的值是一个整数,那么我们目前的问题就转化为有两个数组\(A[]\)和\(B[]\),\(A[]\)数组中有多少个不同的数在\(B[]\)中出现过。那么对于这个问题很显然我们可以建立一个\(bool\)数组\(C[]\)与\(bool\)数组\(used[]\),扫 一遍\(A[]\),以\(A[]\)中的每个元素为下标,赋值为\(true\)。扫一遍\(B[]\),如果\(C[B[i]]==true\)且\(used[B[i]]=false\)那么\(cnt++\),\(used[B[i]]\)赋值为\(true\)。
那么很显然我们就可以用哈希值作为\(C[]\)数组的下标(要保证在求哈希之模的数能作为数组下标)愉快的解决第一个问。
cin >> n;
for (int i = 0; i < n; i++){
cin >> s;
have[hsh(s)] = true;
}
cin >> m;
for (int i = 1; i <= m; i++){
cin >> s;
val[i] = hsh(s);
if (have[val[i]] && !used[val[i]]){
cnt++;
used[val[i]] = true;
}
}
此步复杂度为\(O(m)\)
我们可以枚举长度\(len\)并分别判断从第\(i\)个单词开始为第一个单词的长度为\(len\)子串是否合法(即在\(B[]\)中存在连续的长度为\(k\)的一段,包含\(cnt\)个单词)。其中\(1≤len≤m\),判断的复杂度为\(O(m^2)\)
因此总复杂度为\(O(m^3)\)
在上面所描述的暴力中,我们将第二问转化为了一个判定问题。
而在我们所枚举的集合很显然是具有单调性的:
如果答案为\(k\)
那么如果长度大于\(k\)必然合法
而长度要是小于\(k\)则必然不合法
因此我们可以二分长度\(len\),\(check\)的复杂度为\(O(m^2)\),二分的复杂度为\(O(log\ m)\)因此总复杂度为\(O(m^2\ log\ m)\)。
设\(f_{l,r}\)为从\(B[l]\)到\(B[r]\)这段区间内,包含\(A[]\)中的数的个数。
当\(f_{l,r}=cnt\)且\(C[B[r]]=true\)并满足于\(C[B[r+1]]=false\)时
设其中包含\(cnt\)个\(A[]\)中元素个数的最短区间为\([a,b]\)(等价于\([a,r]\))
那么显然\(f_{a,b}=f_{l,r}=f_{a,r}\)
那么我们则可以用\(r - a + 1\)更新元素
我们维护一个集合\(S\)与\(S‘\),\(S\)包括\(B[l] \sim B[r]\),\(S‘\)包括\(B[a] \sim B[r]\)
那么\((r-l+1)=|S|\),\((r-a+1)=|S‘|\)
我们已知\(l,r\)与集合\(S\),接下来即求出\(a\)与\(S‘\)
因为\(f_{l,r}=f_{a,r}=cnt\)且\([a,r]\)为包含\(cnt\)个\(A[]\)中元素个数的最短区间
那么\(f_{a+1,r}\)必然小于\(cnt\)
且\(f_{l,r-1}\)必然小于\(cnt\)
且\([a,r]\)为连续的一段
因此我们得到\(S‘\)最朴素的做法即从\(l\)开始依次删除\(B[i]\)所对应的集合的元素。对应的区间为\([c,r]\)当\(f_{c,r}<cnt\)时\(r-c+2\)即为\(r - a + 1\)。
因此我们可以枚举\(r\),计算\(f_{1,r}\)并维护集合\(S\),每次枚举插入\(B[r]\)。
当\(f_{1,r}=cnt\)时依次删除前\(i\)个元素,直到\(f_{1,r}<cnt\)
并用\(|S‘|+1\)更新答案。
而对于集合\(S\),因为我们只在一端插入,一端删除,因此可以用队列维护。
而对于每个元素最多进队\(1\)次出队\(1\)次。
因此复杂度为\(O(m)\)。
#include <iostream>
#include <cstring>
#include <queue>
using namespace std;
const int mod = 1000007;
const int base = 131;
bool have[mod], used[mod];
int val[100005],sum[mod];
char s[15];
queue<int> q;
int hsh(char* s){
int ret = 0, len = strlen(s);
for (int i = 0; i < len; i++){
ret = (ret * base + s[i]) % mod;
}
return ret;
}
int main() {
int n, m, cnt = 0, len, now;
cin >> n;
for (int i = 0; i < n; i++){
cin >> s;
have[hsh(s)] = true;
}
cin >> m;
for (int i = 1; i <= m; i++){
cin >> s;
val[i] = hsh(s);
if (have[val[i]] && !used[val[i]]){
cnt++;
used[val[i]] = true;
}
}
if (cnt == 0){
cout << 0 << endl;
cout << 0 << endl;
}else{
len = m;
now = 0;
for (int i = 1; i <= m; i++){
int queuelen = q.size();
q.push(i);
sum[val[i]]++;
if (have[val[i]] && sum[val[i]] == 1) now++;
if (now == cnt){
while (now == cnt){
int v = q.front();
q.pop();
sum[val[v]]--;
if (sum[val[v]] == 0 && have[val[v]]) now--;
}
queuelen = q.size() + 1;
len = min(len,queuelen);
}
}
cout << cnt << endl << len;
}
return 0;
}
标签:因此 front char* cstring 复杂度 为我 check log 元素
原文地址:https://www.cnblogs.com/wxy-max/p/13237700.html