1. 程式人生 > >中石油第四場組隊賽 Prefix Free Code(字典樹+樹狀陣列)

中石油第四場組隊賽 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;
}