JZOJ3126 大LCP(GDKOI 2013)

来源:互联网 发布:五星缩水软件免费版 编辑:程序博客网 时间:2024/06/06 00:27

这是这周CYC出的训练题目之一:
题面:

LCP就是传说中的最长公共前缀,至于为什么要加上一个大字,那是因为…你会知道的。
首先,求LCP就要有字符串。既然那么需要它们,那就给出n个字符串好了。
于是你需要回答询问大LCP,询问给出一个k,你需要求出前k个字符串中两两的LCP最大值是多少,这就是传说中的大LCP。

输入:
第一行一个整数N,Q,分别表示字符串个数和询问次数。
接下来N行,每行一个字符串。
再Q行,每行一个正整数k。
对于30%的数据,字符串总长度不超过10^4,1<=N<=10^3,1<=Q<=10.
接下来30%的数据,字符串总长度不超过10^4,1<=N<=10^3,1<=Q<=1000.
对于100%的数据,字符串总长度不超过10^6,1<=N,Q<=10^5.
输出:
Q行,依次分别表示对Q个询问的答案。

样例输入:
3 3
a
b
ab
1
2
3

样例输出:
0
0
1

题解分析:
这道题从LCP入手,首先想到是Trie来解,那么又要求在线求,画图后理解一下,发现求解LCP可以在插入的时候记录贡献(要比较的一定先插入),那么我们就得按顺序插入,我们就可以对K进行排序,记录K原来的位置,然后统计答案,存一个ans数组,最后输出就行了,至于求解LCP那里,可以画图理解。因为和另一个字符串有LCP的字符串在插入的时候不用新建节点,我们只要统计一下他走过的已经建成的节点有几个就可以求出了。

代码:

# include<cstdio># include<algorithm># include<iostream># include<cstdlib>using namespace std;const int N = 1e5 + 10;struct b{    int val,pos;}k[N];struct node{    node *nex[27];}*root;node *newnode1;int n,q,i,maxx,top;int ans[N];string s[N];void clear(node *p){    for (int i = 0;i < 26; i++)        p->nex[i] = 0;   } int cmp(b x,b y){    return x.val < y.val;}void insert(string s){    int sum = 0; bool j = false;    int len = s.size();    node *p = root;    for (int i = 0;i < len; i++)    {        int c = s[i] - 'a';        if (p->nex[c] == 0)        {            j = true;            newnode1 = (node*)malloc(sizeof (node));            clear(newnode1);            p->nex[c] = newnode1;        }        if (!j) sum ++;        p = p->nex[c];    }    maxx = max(maxx,sum);}int main(){    root = (node*)malloc(sizeof (node));    clear(root); top++;    scanf("%d%d",&n,&q);    for (i = 1;i <= n; i++)        cin>>s[i];    for (i = 1;i <= q; i++)        scanf("%d",&k[i].val),k[i].pos = i;    sort(k + 1,k + q + 1,cmp);    for (i = 1;i <= n; i++)    {        insert(s[i]);        while (i == k[top].val)        {            ans[k[top].pos] = maxx;            top++;        }    }    for (i = 1;i <= q; i++)        printf("%d\n",ans[i]);    return 0;}
原创粉丝点击