中石油第四场组队赛 Prefix Free Code(字典树+树状数组)

问题 E: Prefix Free Code

时间限制: 1 Sec  内存限制: 256 MB
提交: 152  解决: 41
[提交] [状态] [讨论版] [命题人:admin]

题目描述

Consider n initial strings of lower case letters, where no initial string is a prefix of any other initial string. Now, consider choosing k 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)
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 +7. The first composite string in the list is at position 1.

输入

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 n and then k(1 ≤ k ≤ n), where n is the number of initial strings, and k is the number of initial strings you choose to form composite strings. The upper bounds of n and k are limited by the constraints on the strings, in the following paragraphs.
Each of the next n lines will contain a string, which will consist of one or more lower case letters a..z. These are the n 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..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 k unique initial strings.
The sum of the lengths of all input strings, including the test string, will not exceed 106 letters.

输出

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 + 7.

样例输入

5 3
a
b
c
d
e
cad

样例输出

26

题意:从n个字符串中拿出m个的全排列按字典序排列,询问一个字符串在其中是第几个。

题解:终于遇到这样的数据结构了!!开心,不过这道题却是在最后半个小时看到的,不过还是在不懈的努力了通过了,哈。

首先根据题意,给出的n个字符串任一都不是其中一个的前缀,那么我们可以将n个字符串根据字典序进行排序,那么给出的字符串s便可以表示为m个数字的组合,根据排列组合可得,枚举每一位,答案即为A(n-i,m-i)*num(比这个数字小且前面未出现的数的个数)求和即可,对于这个式子中的num可以用树状数组进行维护,找到字符串的数字组成可以用字典树进行存储。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
const int maxn=1e6+7;
int tire[maxn][26],fina[maxn],cnt=1,num=0,n,m;

void ins(char s[])
{
    int rt=1;
    int len=strlen(s);
    for(int i=0;i<len;i++)
    {
        int tmp=s[i]-'a';
        if(!tire[rt][tmp])
            tire[rt][tmp]=++cnt;
        rt=tire[rt][tmp];
    }
    fina[rt]=1;//标记该位置为单词结尾
}

void dfs(int s)
{
    int sum=0;
    for(int i=0;i<26;i++)
    {
        if(tire[s][i]) dfs(tire[s][i]);
        sum|=tire[s][i];
    }
    if(sum==0 && fina[s]) fina[s]=++num;//记录该单词按字典序排列的序号
}

vector<int>v;
void find(char s[])
{
    int rt=1,i=0;
    int len=strlen(s);
    while(1)
    {
        rt=1;
        for(;i<len;i++)
        {
            int tmp=s[i]-'a';
            rt=tire[rt][tmp];
            if(fina[rt])
            {
                v.push_back(fina[rt]);
                i++;
                break;
            }
        }
        if(i==len) return;
    }
}

int tree[maxn];
void add(int x,int v)
{
    for(;x<=n;x+=x&-x)
        tree[x]+=v;
}

ll query(int x)
{
    int ans=0;
    for(;x;x-=x&-x)
        ans+=tree[x];
    return ans;
}

ll qpow(ll a,ll b)
{
    ll ans=1;
    while(b)
    {
        if(b&1)
            ans=(ans*a)%mod;
        a=(a*a)%mod;
        b/=2;
    }
    return ans;
}

char s[1000005],ss[1000005];
ll fac[maxn];
int main()
{
    fac[0]=1;
    for(int i=1;i<maxn;i++)
        fac[i]=fac[i-1]*i%mod;
    scanf("%d%d",&n,&m);

    ll inv=qpow(fac[n-m],mod-2);
    for(int i=0;i<n;i++)
    {
        scanf("%s",s);
        ins(s);
    }

    scanf("%s",ss);
    dfs(1);
    find(ss);

    ll ans=0;
    for(int i=0;i<v.size();i++)
    {
        ans=(ans+max(0LL,(v[i]-1-query(v[i])))%mod*fac[n-i-1]%mod*inv%mod)%mod;
        add(v[i],1);
    }

    printf("%lld\n",(ans+1)%mod);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/sudu6666/article/details/82153341
今日推荐