JZOJ3126 大LCP(GDKOI 2013)

这是这周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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值