【ACWing】4398. 查询字符串

题目地址:

https://www.acwing.com/problem/content/description/4401/

给定 n n n个字符串 f 1 , f 2 , … , f n f_1,f_2,…,f_n f1,f2,,fn。这些字符串两两不同。下面给定 q q q个询问。其中,第 i i i次询问给定一个字符串 s i s_i si,你的任务是:计算 f 1 ∼ f n f_1∼f_n f1fn n n n个字符串中,包含 s i s_i si作为子串的字符串的数量。从 f 1 ∼ f n f_1∼f_n f1fn n n n个字符串中,任选一个包含 s i s_i si作为子串的字符串输出。

输入格式:
第一行包含整数 n n n
接下来 n n n行,其中第 i i i行包含字符串 f i f_i fi
再一行包含整数 q q q
接下来 q q q行,其中第 i i i行包含字符串 s i s_i si
所有 f i f_i fi s i s_i si都只包含小写字母、数字以及.

输出格式:
q q q行,其中第 i i i行输出第 i i i个询问的答案。
首先输出 f 1 ∼ f n f_1∼f_n f1fn n n n个字符串中包含 s i s_i si作为子串的字符串的数量。然后从 f 1 ∼ f n f_1∼f_n f1fn n n n个字符串中任选一个包含 s i s_i si作为子串的字符串输出。
如果这样的字符串不唯一,则输出任意合理字符串均可,如果这样的字符串不存在,则输出-

数据范围:
前三个测试点满足 1 ≤ n , q ≤ 20 1≤n,q≤20 1n,q20
所有测试点满足 1 ≤ n ≤ 10000 1≤n≤10000 1n10000 1 ≤ q ≤ 50000 1≤q≤50000 1q50000 1 ≤ ∣ f i ∣ , ∣ s i ∣ ≤ 8 1≤|f_i|,|s_i|≤8 1fi,si8

观察到每个字符串都很短,可以直接用两个哈希表,一个存每个子串出现在多少个原串里,另一个存每个子串存在于哪个原串里。代码如下:

#include <iostream>
#include <unordered_map>
#include <unordered_set>
#include <vector>
using namespace std;

unordered_map<string, int> mp, mp1;
unordered_set<string> st;
vector<string> vs;
int n, q;

int main() {
  scanf("%d", &n);
  string s;
  for (int i = 0; i < n; i++) {
    cin >> s;
    vs.push_back(s);
    st.clear();
    for (int j = 0; j < s.size(); j++)
      for (int k = j; k < s.size(); k++) {
        auto t = s.substr(j, k - j + 1);
        if (!st.count(t)) {
          st.insert(t);
          mp1[t] = i;
          mp[t]++;
        }
      }
  }
  scanf("%d", &q);
  while (q--) {
    cin >> s;
    if (!mp[s])
      puts("0 -");
    else
      cout << mp[s] << " " << vs[mp1[s]] << endl;
  }
}

预处理时间复杂度 O ( ∑ i l i 3 ) O(\sum_i l_i^3) O(ili3),每次查询时间 O ( l s ) O(l_s) O(ls),空间 O ( ∑ i l i ) O(\sum_i l_i) O(ili)

  • 18
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值