P2336 [SCOI2012] 喵星球上的点名 sol 目前最优解
最优解,乐。
题解区全是很厉害的做法啊,可惜我只能领略一二。
有一种很亲民的做法:哈希,代码巨短无比(当然我的 record 带一个很长的头罢了)。
我们发现一个事实:
我们现在考虑第二问应该怎么做?
我们先处理出这
然后再考虑到第一问:
我们现在已经记录了
注意你的哈希不要让
时间复杂度
可以参考一下我的答辩代码:
ull h[N], g[N];
inline ull hsh(int l, int r) {
if (!l) return h[r];
return h[r] - h[l - 1] * g[r - l + 1];
}
hash_map vis, mp;
unordered_map<ull, int> mp_;
int n, m, ans[N];
int main() {
read(n), read(m), g[0] = 1;
for (int i = 1; i < N; i++) g[i] = g[i - 1] * P;
for (int i = 1; i <= n; i++) {
int x, y;
read(x); while (x--) read(y), ++y, str[i].push_back(y);
read(x); while (x--) read(y), ++y, str2[i].push_back(y);
}
vector<int> v;
for (int i = 1; i <= m; i++) {
int x, y;
read(x), v.emplace_back(x); ull ans = 0;
while (x--) read(y), ++y, ans = ans * P + y;
f[i] = ans, ++vis[ans];
}
sort(v.begin(), v.end()), v.erase(unique(v.begin(), v.end()), v.end());
for (int i = 1; i <= n; i++) {
clear(mp_), h[0] = str[i][0];
int res = 0;
for (int j = 1; j < str[i].size(); j++) h[j] = h[j - 1] * P + str[i][j];
for (int len : v)
for (int j = len - 1; j < str[i].size(); j++) {
ull tmp = hsh(j - len + 1, j);
if (vis.count(tmp) && !mp_.count(tmp)) ++mp_[tmp], res += vis[tmp];
}
h[0] = str2[i][0];
for (int j = 1; j < str2[i].size(); j++)
h[j] = h[j - 1] * P + str2[i][j];
for (int len : v)
for (int j = len - 1; j < str2[i].size(); j++) {
ull tmp = hsh(j - len + 1, j);
if (vis.count(tmp) && !mp_.count(tmp)) ++mp_[tmp], res += vis[tmp];
}
ans[i] = res;
for (auto [u, v] : mp_) ++mp[u];
}
for (int i = 1; i <= m; i++) write(mp[f[i]]), putc('\n');
for (int i = 1; i <= n; i++) write(ans[i]), putc(' ');
do_flush();
return 0;
}