bzoj 1590: [Usaco2008 Dec]Secret Message 祕密資訊
阿新 • • 發佈:2018-12-17
簡述題意:
給你n個字串,再給你m個字串,詢問這m個字串中有多少成為n個字串的子串(或n個字串中有多少成為m個字串的子串)
演算法:trie樹
難度:NOIP
時間複雜度:
題解:就是裸跑trie樹,注意統計答案的方式!
sum表示以這個結點結尾的字串的個數;
summ表示經過此結點的次數;
程式碼如下:
#include <cstdio> #include <iostream> #include <cstring> #include <cmath> #include <algorithm> #define ll long long #define N 50005 #define M 500005//注意陣列大小!!! using namespace std; int sum[M],summ[M]; int trie[M][5]; int cnt=1,k; int str[N]; void insert(int m[]) { int now=0; for(int i = 1;i <= k;i++) { int tem=m[i]; if(trie[now][tem]==0) { trie[now][tem]=cnt++; } now=trie[now][tem]; summ[now]++; } sum[now]++; } int check(int m[]) { int ret=0; int now=0; bool fla=0; for(int i = 1;i <= k;i++) { int temp=m[i]; if(!trie[now][temp]) { fla=1; break; } ret+=sum[now];//① now=trie[now][temp];//② } ret+=sum[now];//如果①位置與②位置調換,則不用寫這句話,否則最後一個位置的sum沒加到ret上! if(!fla) { ret+=summ[now]; ret-=sum[now]; } return ret; } int main() { int n,km; scanf("%d%d",&km,&n); for(int i = 1;i <= km;i++) { scanf("%d",&k); for(int j = 1;j <= k;j++) { scanf("%d",&str[j]); } insert(str); } for(int i = 1;i <= n;i++) { scanf("%d",&k); for(int j = 1;j <= k;j++) { scanf("%d",&str[j]); } printf("%d\n",check(str)); } return 0 ; }