1115: 最短的名字

本文介绍了一种用于确定最短唯一姓名缩写的算法,适用于一个特殊村庄中居民名字的特殊情况。通过构造特定的数据结构和比较逻辑,算法能够高效地计算出每个村民最短且不与他人混淆的名字缩写,进而求得所有名字缩写的总字符数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description

在一个奇怪的村子中,很多人的名字都很长,比如aaaaa, bbb and abababab。
名字这么长,叫全名显然起来很不方便。所以村民之间一般只叫名字的前缀。比如叫'aaaaa'的时候可以只叫'aaa',因为没有第二个人名字的前三个字母是'aaa'。不过你不能叫'a',因为有两个人的名字都以'a'开头。村里的人都很聪明,他们总是用最短的称呼叫人。输入保证村里不会有一个人的名字是另外一个人名字的前缀(作为推论,任意两个人的名字都不会相同)。
如果村里的某个人要叫所有人的名字(包括他自己),他一共会说多少个字母?

Input

输入第一行为数据组数T (T<=10)。每组数据第一行为一个整数n(1<=n<=1000),即村里的人数。以下n行每行为一个人的名字(仅有小写字母组成)。输入保证一个村里所有人名字的长度之和不超过1,000,000。

Output

对于每组数据,输出所有人名字的字母总数。

Sample Input

1
3
aaaaa
bbb
abababab

Sample Output

5

坑爹啊!不能用gets

#include<iostream>
#include<cstdio>
#include<cstring>
#include<stdio.h>
#include<algorithm>
#include<queue>
using namespace std;
const long long MAX = 1000000+10000;
char s[MAX];
char r[MAX];
long long n,E;
struct node{
    long long s,e;
}g[1000+100];
bool cmp(node a,node b)
{
    long long i=a.s,j=b.s;
    while(i<=a.e&&j<=b.e)
    {
        if(s[i]<s[j])
        {
            return true;
        }else if(s[i]>s[j]){
            return false;
        }
        i++;j++;
    }
    if(i>a.e)
        return true;
    return false;
}
long long find_ct(long long i,long long &w)
{
    long long x=g[i].s,y=g[i+1].s;
    long long k=0;
    while(x<=g[i].e&&y<=g[i+1].e)
    {
        if(s[x]==s[y])
        {
            k++;
        }else{
            if(k<w)
            {
                long long aa=w;
                w=k;
                return aa+1;
            }else{
                w=k;
                return k+1;
            }
        }
        x++;y++;
    }
    w=k;
    return k;
}
int main()
{
    long long t;
    cin>>t;
    while(t--){
        cin>>n;
        long long i,j;
        E=0;
        for(i=0; i<n; i++)
        {
            cin>>r;
            long long k,len=strlen(r);
            for(j=E,k=0; k<len; j++,k++)
            {
                s[j]=r[k];
            }
            g[i].s=E;
            E+=len;
            g[i].e=E-1;
        }
        sort(g,g+n,cmp);
        /*for(i=0;i<n;i++)
        {
            for(j=g[i].s;j<=g[i].e;j++)
                cout<<s[j];
            cout<<endl;
        }*/
        long long ans=0,w=0;
        for(i=0; i<n-1; i++)
        {

            ans+=find_ct(i,w);  //1cout<<ans<<" "<<w<<endl;
        }
        ans+=w+1;
        cout<<ans<<endl;
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值