前言:
這個題一直有個疑問,最多一千行,每行五千字$1000\times5000=5e6$
$5e6\times26\times4\div1024\div1024\approx496Mb>125Mb$
儘管清楚實際空間需求不能到達$5e6$,如何計算直接對文章建$Trie$事實上所需的最大空間呢,本人對此並不清楚,也但願有大佬能爲我解決一下這個問題(至於開$5e6\times26$經過的大佬,我想我這種凡人還達不到這個境界)
那麼,就請咱們權且認爲直接對文章建$Trie$在空間上是不被容許的,至少是不夠保險的
正文:
因而提供一種一樣是基於$Trie$的方法——對詢問建$Trie$
$10000\times20\times26\times4\div1024\div1024\approx20Mb$
佔空間最多的$Trie$解決了,空間問題就沒必要擔憂了
下面咱們考慮對詢問建$Trie$下這個問題的解決
(這不是$Trie$的板子題嗎,有什麼可考慮的)
好吧,代碼實現細節及一些注意事項,見代碼了
ios
#include<iostream> #include<cstdio> #include<cstring> #include<vector> #include<algorithm> using namespace std; const int maxn=5e6,maxq=2e5+10; int cnt,a[maxq][26],n,m; vector<string>v[1010]; vector<int>ans[10010],val[maxq]; string tmp; int idx(char c) { return c-'a'; } void insert(int x) { cin>>tmp; int len=tmp.length(),now=0; for(int i=0;i<len;i++) { int c=idx(tmp[i]); now=a[now][c]?a[now][c]:a[now][c]=++cnt; } val[now].push_back(x); /*由於可能有相同的查詢,這裏的簡單地用一個 整形標記就不太合適了,我選擇了用vector記錄 這個節點做爲全部詢問的標記*/ } void check(int x,int y) { int len=v[x][y].length(),now=0; for(int i=0;i<len;i++) { int c=idx(v[x][y][i]); if(!a[now][c]) return; //這個單詞必定沒有被查詢過,直接退回 now=a[now][c]; } for(int i=0;i<val[now].size();i++) ans[val[now][i]].push_back(x); //同理在全部詢問中保存這個單詞曾經出現的文章 } int main() { scanf("%d",&n); for(int i=1,num;i<=n;i++) { scanf("%d",&num); for(int j=1;j<=num;j++) { cin>>tmp; v[i].push_back(tmp); //採用了vector來存儲原文 } } scanf("%d",&m); for(int i=1;i<=m;i++) insert(i); for(int i=1;i<=n;i++) for(int j=0;j<v[i].size();j++) check(i,j); for(int i=1;i<=m;i++) { vector<int>::iterator pos=unique(ans[i].begin(),ans[i].end()); for(vector<int>::iterator it=ans[i].begin();it!=pos;it++) printf("%d ",*it); printf("\n"); } /*這裏的輸出,由於一篇文章裏可能屢次出現同一單詞, 記得去重,一開始我用的unique,再輸出vector中的 全部元素。可是unique去重時其實並無刪除這些元素 在這裏也被坑了,因此改用迭代器*/ return 0; }