G - Most Common Suffix Gym - 101502G 按边建边+思维

G. Most Common Suffix

time limit per test

1.0 s

memory limit per test

512 MB

input

standard input

output

standard output

You are given n strings, and q queries. For each query i, your task is to find the most common suffix of length xi, you need to print how common it is.

The suffix i (or the ith suffix) of a string is a special case of substring that goes from the ith character of the string up to the last character of the string. For example, the 4th suffix of "development" is "lopment", the 7th suffix of "development" is "ment" (0-based indexing).

Input

The first line contains an integer T (1 ≤ T ≤ 75), where T is the number of test cases.

The first line of each test case contains two integers n and q (1 ≤ n, q ≤ 104), where n is the number of strings, and q is the number of queries.

Then n lines follow, each line contains a string s, giving the strings. All strings are non-empty consisting of lowercase English letters.

Then q lines follow, each line contains an integer x (1 ≤ x ≤ m), giving the queries. Where m equals the length of the longest string among the given n strings.

The total length of strings in each test case does not exceed 105.

Output

For each query, print a single line containing the answer.

Example

input

1
5 4
abccba
abddba
xa
abdcba
aneverknow
1
2
4
3

output

4
3
1
2

Note

As input/output can reach huge size it is recommended to use fast input/output methods: for example, prefer to use scanf/printfinstead of cin/cout in C++, prefer to use BufferedReader/PrintWriter instead of Scanner/System.out in Java.


题意:给你n个字符串,q个询问,每次询问会给出一个长度len,问最长公共后缀为len的字符串有多少。

做法:按照当前位置x建边,结点中存该位置的字母x和该位置如果对应上了之后的下一条边next。

很神奇的图论题,参考了大大的代码才做出来的。


代码如下:

#include<bits/stdc++.h>
using namespace std;
const int maxn=100005;
struct node{
    char x;
    int num,next;
}e[maxn];
int head[maxn],ans[maxn],now;
char s[maxn];
int deal(int x,char y){
    for(int i=head[x];~i;i=e[i].next){//找当前边所含字符与给定字符是否相等
        if(e[i].x==y){
            e[i].num++;
            return i;
        }
    }
    e[++now].num=1,e[now].x=y,e[now].next=head[x],head[x]=now;//如果没有则以该边为一个结点建立新的边
    return now;
}
int main(){
    int t,n,q,qs;
    cin>>t;
    while(t--){
        memset(head,-1,sizeof(head));
        memset(ans,0,sizeof(ans));
        now=0;
        scanf("%d%d",&n,&q);
        for(int i=1;i<=n;i++){
            scanf("%s",s+1);
            int len=strlen(s+1),cur=0;
            for(int j=len;j>=1;j--){
                cur=deal(cur,s[j]);//进入的是当前边,返回的是该边对应的有最多公共字符的那条边或新建立的边,影响下一层
                ans[len-j+1]=max(ans[len-j+1],e[cur].num);
            }
        }
        for(int i=1;i<=q;i++){
            scanf("%d",&qs);
            printf("%d\n",ans[qs]);
        }
    }
    return 0;
}

本内容为原创,可能会有错误,如有问题欢迎联系

猜你喜欢

转载自blog.csdn.net/qq_41955236/article/details/81583642