CodeForces 858D Polycarp's phone book(Trie)

来源:互联网 发布:数据对比分析的方法 编辑:程序博客网 时间:2024/05/24 06:48

Polycarp's phone book

time limit per test:4 seconds

memory limit per test:256 megabytes

input:standard input

output:standard output

There are n phone numbers in Polycarp's contacts on his phone. Each number is a 9-digit integer, starting with a digit different from0. All the numbers are distinct.

There is the latest version of Berdroid OS installed on Polycarp's phone. If some number is entered, is shows up all the numbers in the contacts for which there is a substring equal to the entered sequence of digits. For example, is there are three phone numbers in Polycarp's contacts: 123456789, 100000000 and 100123456, then:

  • if he enters 00 two numbers will show up: 100000000 and 100123456,
  • if he enters 123 two numbers will show up 123456789 and 100123456,
  • if he enters 01 there will be only one number 100123456.

For each of the phone numbers in Polycarp's contacts, find the minimum in length sequence of digits such that if Polycarp enters this sequence, Berdroid shows this only phone number.

Input

The first line contains single integer n (1 ≤ n ≤ 70000) — the total number of phone contacts in Polycarp's contacts.

The phone numbers follow, one in each line. Each number is a positive 9-digit integer starting with a digit from1 to9. All the numbers are distinct.

Output

Print exactly n lines: the i-th of them should contain the shortest non-empty sequence of digits, such that if Polycarp enters it, the Berdroid OS shows up only thei-th number from the contacts. If there are several such sequences, print any of them.

Examples
Input
3123456789100000000100123456
Output
900001
Input
4123456789193456789134567819934567891
Output
21938191



        大致题意,给出很多个号码,然后要你对每一个号码找出一个长度最短的识别码,即长度最短的同时,只有那一个电话包含这个识别码。

        这里队友机智无比,直接想到用字典树搞。由于号码最多只有10位,所以对于每一个号码,在字典树里面分别加入第0位~最后一位,第1位~最后一位,第2位~最后一位……这样解决了字典树只能一定要从头开始的缺陷。如此一来对于一个号码的任意一个小段,我们都可以对应在字典树中找到一个从根开始的路径与之对应。那么我们要做的就是统计一直到任意小段的最后一位的节点,有多少个这样的子串包含这个小段。如果只有一个包含这个小段,那么这个小段可以作为特征码。对于这个小段,由于长度较短,我们直接进行枚举即可,logN判断。

        这样子写了之后,发现样例过不了……我们观察第一个样例的第二个号码1000000000,注意到我们加入字典树的时候,加入了很多个只含有0的子串,那么在我们判断的时候,对于000这个合法的特征码,在字典树中查询的时候出来会显示多个匹配的串。实际上,这些只含有0的串都是统一号码提供的,并不应该被统计进去。那么就有一个新的问题,如何判定哪些要统计。这时,我有机智的脑补,直接加一个时间戳就行了,对于每一个点,我都加一个时间戳,表示该点是被哪一个号码更新的,如果是统一号码,那么在统计size的时候就不把这个统计进去,否则统计。巧妙地解决了这个问题。具体见代码:

#include <bits/stdc++.h>#define N 100010using namespace std;struct Trie{    struct node{int size,ch[10],t;}T[N<<5];    int tot,root;    void init()    {        tot=root=1;        memset(T,0,sizeof(T));    }    void ins(char* x,int t)//t为时间戳    {        int o=root;        if (T[o].t!=t){T[o].size++;T[o].t=t;}//如果时间戳不相同则增加,否则不        for(int k=0;k<strlen(x);k++)        {            int c=x[k]-48;            if(!T[o].ch[c]) T[o].ch[c]=++tot;            o=T[o].ch[c];            if (T[o].t!=t){T[o].size++;T[o].t=t;}        }    }    int query(char* x)    {        int o=root;        for(int k=0;k<strlen(x);k++)        {            int c=x[k]-48;            o=T[o].ch[c];        }        return T[o].size;    }} Trie;char str[N][10],s[10];int n;int main(){    scanf("%d\n",&n);    for(int i=1;i<=n;i++)        {            scanf("%s",str[i]);            for(int j=0;j<strlen(str[i]);j++)            {                strcpy(s,str[i]+j);//把每一位到最后的子串加到字典树中                Trie.ins(s,i);            }        }    for(int i=1;i<=n;i++)    {        bool flag=0;        for(int len=1;len<=strlen(str[i]);len++)        {            for(int b=0;b+len-1<strlen(str[i]);b++)            {                memset(s,0,sizeof(s));                for(int j=0;j<len;j++)                    s[j]=str[i][j+b];//暴力枚举特征码,从短的开始枚举                if (Trie.query(s)==1) {flag=1;break;}//如果只出现一次,那么合法,直接输出            }            if (flag) {printf("%s\n",s); break;}        }    }    return 0;}

阅读全文
0 0
原创粉丝点击