看大神代码,发现上交大神很棒的一个思路
题意:
在源数字串中找出尽量多的连续子串,要求子串任意两值的大小关系与目标串相同位置的值的大小关系相同。求源串能拿出的子串的最大数量。
关键词:
RK-Hash
优点:
O(k)时间完成匹配检查(关键在于他能O(1) 完成 所有 相同位 检查)
方法:
对于一个K值,用某个进制数来表示其位置。
比如 123121 中 的值 1 最后表示成 100101。
然后,对于目标串也RK-hash,对于某个值,只要比较这个数,就能知道是否相同位都相同了。
代码留恋:
#include<vector> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; const int N = 100005, K = 26; int a[N], b[N], n, m, k; unsigned long long phs[K], ahs[K], DEF; const unsigned long long base = 29; int main() { while (scanf("%d%d%d", &n, &m, &k) == 3) { for (int i = 0; i < n; ++i) { scanf("%d", a + i); } for (int i = 0; i < m; ++i) { scanf("%d", b + i); } DEF = 1; for (int i = 0; i < m - 1; ++i) { DEF *= base; } memset(phs, 0, sizeof(phs)); memset(ahs, 0, sizeof(ahs)); for (int i = 0; i < m; ++i) { for (int j = 0; j < k; ++j) { phs[j] *= base; } phs[b[i] - 1] += 1; } vector<int> v; for (int i = 0; i < n; ++i) { for (int j = 0; j < k; ++j) { ahs[j] *= base; } ahs[a[i] - 1] += 1; if (i >= m - 1) { int t1 = k - 1, t2 = k - 1; bool sue = false; while (true) { while (t1 >= 0 && ahs[t1] == 0) { --t1; } while (t2 >= 0 && phs[t2] == 0) { --t2; } if (t1 == -1 && t2 == -1) { sue = true; break; } if (t1 == -1 || t2 == -1) { break; } if (ahs[t1] != phs[t2]) { break; } --t1, --t2; } if (sue) { v.push_back(i - m + 1); } ahs[a[i - m + 1] - 1] -= DEF; } } int last = -m - 5, ans = 0; for (int i = 0; i < (int)v.size(); ++i) { if (v[i] < last + m) { continue; } else { last = v[i]; ++ans; } } printf("%d ", ans); } return 0; }