#include #include #include #include using namespace std; const int N = 5e5+5; int ans,cnt,nxt[N],ch[N][30],bo[N]; void make(char *s){ // 构建trie树 int u = 1, len = strlen(s); for(int i=0;i que; for(int i=0;i<26;++i){ ch[0][i] = 1; // 为了方便将 0 的所有转移边都设为根节点1(所有转移边都存在,属于虚构部分) } nxt[1] = 0;//若在根节点失配,则无法匹配字符 que.push(1); while(!que.empty()){ int u = que.front(); que.pop(); for(int i=0;i<26;++i){ if( !ch[u][i] ){ ch[u][i] = ch[nxt[u]][i]; // 此处为优化 } else{ que.push(ch[u][i]);//若有节点u这个儿子,则将其加入队列中 int v = nxt[u]; //获取节点u的 fail指针 nxt[ch[u][i]] = ch[v][i]; } } } } void find(char* s){ int u = 1,len = strlen(s),c,k; for(int i=0;i1 ){ ans += bo[k]; bo[k] = 0; k = nxt[k]; } u = ch[u][c]; } return; } int main(){ int t,n; char s[N<<1]; scanf("%d",&t); while(t--){ ans = 0;cnt = 1; memset(bo,0,sizeof(bo)); for(int i=0;i<26;i++){ ch[0][i] = 1; ch[1][i] = 0; } scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%s",s); make(s); } bfs(); for(int i=0;i<=25;i++){ for(int j=0;j<=20;j++){ cout<