Prefix Free Code 解题报告

Consider nn initial strings of lower case letters, where no initial string is a prefix of any other initial string. Now, consider choosing kk of the strings (no string more than once), and concatenating them together. You can make this many such composite strings:

n×(n−1)×(n−2)×…×(n−k+1)n×(n−1)×(n−2)×…×(n−k+1)

Consider sorting all of the composite strings you can get via this process in alphabetical order. You are given a test composite string, which is guaranteed to belong on this list. Find the position of this test composite string in the alphabetized list of all composite strings, modulo 109+7109+7. The first composite string in the list is at position 11.

Input

Each input will consist of a single test case. Note that your program may be run multiple times on different inputs. Each test case will begin with a line with two integers, first nn and then kk (1≤k≤n1≤k≤n), where nn is the number of initial strings, and kk is the number of initial strings you choose to form composite strings. The upper bounds of nn and kk are limited by the constraints on the strings, in the following paragraphs.

Each of the next nn lines will contain a string, which will consist of one or more lower case letters a..za..z. These are the nn initial strings. It is guaranteed that none of the initial strings will be a prefix of any other of the initial strings.

Finally, the last line will contain another string, consisting of only lower case letters a..za..z. This is the test composite string, the position of which in the sorted list you must find. This test composite string is guaranteed to be a concatenation of kk unique initial strings.

The sum of the lengths of all input strings, including the test string, will not exceed 106106 letters.

Output

Output a single integer, which is the position in the list of sorted composite strings where the test composite string occurs. Output this number modulo 109+7109+7.

Sample Input 1Sample Output 1
5 3
a
b
c
d
e
cad
26
Sample Input 2Sample Output 2
8 8
font
lewin
darko
deon
vanb
johnb
chuckr
tgr
deonjohnbdarkotgrvanbchuckrfontlewin
1

题目大意:

      给你N个单词,从中选K个单词组合成一个句子,问这个句子是所有由K个单词组成的句子中的第几个。

解题过程:

     一开始最简单的思路是,看所给句子中的单词是所有单词中的第一几个,然后根据常用的排列组合求解,但是这道题单纯的用数组储存所有单词在进行单词是所有单词中的第几个时会大大的增加时间复杂度,即使对单词进行排序后,还有就是我们需要不断的进行所使用单词的更新,因为先使用的单词会对后面单词的计算构成影响,所以这道题就要求我们使用两种数据结构,一种是字典树,一种是线段树或者树状数组。这道题涉及的知识点以及它的应用还有最后排列组合的应用都十分的好,虽然卡的时间很长,但还是收获非常的多,希望学习完知识点后尝试自己解决。

树状数组:https://blog.csdn.net/NCC__dapeng/article/details/88011188

字典树:https://blog.csdn.net/NCC__dapeng/article/details/87944507

线段树:https://blog.csdn.net/NCC__dapeng/article/details/88011424

下面给出AC代码,其中会附带一些必要的解释,注意这道题的一个小坑点就是,排列组合计算的数组必须开long long 否则会在运算过程中出现溢出的问题:

#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
const int maxn=1e6+100;
const int INF=0x3f3f3f3f;
const ll mod=1e9+7;
int c[maxn];
int n,k,cnt=1;//cnt用来记录在所有单词中的字典序
ll sum=1,fac[maxn];
string str[maxn];

//树状数组

int lowbit(int x)
{
    return x&-x;
}

void update(int x,int val)
{
    while(x<=n)
    {
        c[x]+=val;
        x+=lowbit(x);
    }
}

int getsum(int x)
{
    int res=0;
    while(x>0)
    {
        res+=c[x];
        x-=lowbit(x);
    }
    return res;
}


//字典树

struct TireTree
{
    int idex;
    TireTree *next[26];
    TireTree()
    {
        idex=-1;
        memset(next,0,sizeof(next));
    }
}*root;


void init()
{
    root=new TireTree();

    fac[0]=1;
    fac[1]=n-k+1;
    for(int i=2;i<=k;i++)
    {
        fac[i]=fac[i-1]*(n-k+i)%mod;
    }

}

void BuildTire(string s)
{
    TireTree *p=root;
    int len=s.size();
    for(int i=0;i<len;i++)
    {
        if(p->next[s[i]-'a']==NULL)
        {
            p->next[s[i]-'a']=new TireTree();
        }
        p=p->next[s[i]-'a'];
    }
    p->idex=cnt++;
}

void SearchTireTree(string s)
{
    TireTree *p=root;
    int ans=k-1;
    int len=s.size();
    for(int i=0;i<len;i++)
    {

        p=p->next[s[i]-'a'];
        if(p->idex!=-1)
        {
            sum=(fac[ans--]*(p->idex-getsum(p->idex)-1)+sum)%mod;
            update(p->idex,1);
            p=root;
        }
    }
}


int main()
{
    ios::sync_with_stdio(false);
    cin>>n>>k;
    init();
    for(int i=0;i<n;i++) cin>>str[i];
    sort(str,str+n);

    for(int i=0;i<n;i++) BuildTire(str[i]);

    string strm; cin>>strm;
    SearchTireTree(strm);

    cout<<sum<<endl;

    return 0;

}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值