P2922 [USACO08DEC]秘密消息Secret Message
传送门
思路:
还是比较水的(不看题解不看书),用 vis 存字典树上的每个点是多少个单词的前缀,bo 来存每个点是多少个单词的结尾(坑点:会有很多相同的单词,不能只有 bool 来存)。统计时:① 如果匹配串的长度小于单词的长度,ans+= vis;② 如果匹配串的长度≥单词长度,ans+=bo;③ 如果遇到字典树上的节点为空,直接返回。
标程:
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> #include<string> #include<cstdlib> #include<stack> #include<vector> #include<queue> #include<deque> #include<map> #include<set> using namespace std; #define max(a,b) ((a)>(b)?(a):(b)) #define min(a,b) ((a)<(b)?(a):(b)) #define maxn 500002 typedef long long LL; LL n,m,len,cnt=0,ans=0; LL a[maxn],ch[maxn][2],vis[maxn],bo[maxn]; inline LL read() { LL kr=1,xs=0; char ls; ls=getchar(); while(!isdigit(ls)) { if(!(ls^45)) kr=-1; ls=getchar(); } while(isdigit(ls)) { xs=(xs<<1)+(xs<<3)+(ls^48); ls=getchar(); } return xs*kr; } inline void insert() { LL u=0; for(LL i=1;i<=len;i++) { if(!ch[u][a[i]]) ch[u][a[i]]=++cnt; u=ch[u][a[i]]; vis[u]++; } bo[u]++; } inline void find() { LL u=0; for(LL i=1;i<=len;i++) { if(!ch[u][a[i]]) return; u=ch[u][a[i]]; if(bo[u]&&i<len) ans+=bo[u]; } ans+=vis[u]; } int main() { freopen("S.in","r",stdin); freopen("S.out","w",stdout); n=read();m=read(); for(LL i=1;i<=n;i++) { len=read(); for(LL j=1;j<=len;j++) a[j]=read(); insert(); } for(LL i=1;i<=m;i++) { ans=0; len=read(); for(LL j=1;j<=len;j++) a[j]=read(); find(); printf("%lld\n",ans); } return 0; }