1. 程式人生 > >EXAM-2018-08-26

EXAM-2018-08-26

方法 lse har 開始 rap man mem include ram

NAIPC2018

參考:http://www.cnblogs.com/LQLlulu/p/9513669.html?tdsourcetag=s_pctim_aiomsg
https://www.cnblogs.com/clrs97/p/8730429.html?tdsourcetag=s_pctim_aiomsg

E-Pre?x Free Code

題目描述

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

一開始的思路:

用map把輸入的字符串按字典序標記一個數字,因為涉及到排序和map 就要用string。然後再將要處理的字符串也化為數字,然後就是求這個排列是第幾個,對於每位數字,減去前面有多少比它小的-1,然後乘以後面的全排列就好了。終於找前面有多少個比它小的,當然是暴力啦1e6/2=1e3最後半小時才意識到要用樹狀數組,然而還是內存超限。

正解:

怎麽沒想到字典樹呢?好吧其實是想到的但是不會先建樹,因為題中說沒有單詞是另一個單詞的前綴,cnt[]維護每個單詞的編號。然後再用一個num[]維護一下單詞的字典次序,這個怎麽維護呢?直接跑一遍tire,就可以了。num[cnt[u]]相當於之前方法的字符串轉化為數字:正好復習一下tire模板

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=1e6+5;
const int mod=1e9+7;
int n,k,ant;
int s[maxn],c[maxn],cnt[maxn],num[maxn];
int tire[maxn][30];
ll f[1000010],invf[1000010];
char str[maxn];
ll qmul(ll a,ll b){ll ret=0; while(b){ if(b&1) ret=(ret+a)%mod; a=(a+a)%mod; b>>=1;} return ret;}
ll qpow(ll a,ll b){ll ret=1; while(b){ if(b&1) ret=qmul(ret,a); a=qmul(a,a); b>>=1;} return ret;}
void init(){
  f[0]=1;
  for(ll i=1;i<=1000001;i++) f[i]=f[i-1]*i%mod;
  invf[1000001]=qpow(f[1000001],mod-2);
  for(ll i=1000000;i>=0;i--) invf[i]=invf[i+1]*(i+1)%mod;
}
inline int lowbit(int x){return x&-x;}
inline void add(int x,int val){
  for(int i=x;i<=n;i+=lowbit(i)){
    c[i]+=val;
  }
}
inline int getsum(int x){
    int ret=0;
    for(int i=x;i>0;i-=lowbit(i)){
        ret+=c[i];
    }
    return ret;
}
void ins(char *str)
{
    int len=strlen(str);
    int p=0;
    for(int i=0;i<len;i++){
        int ch=str[i]-'a';
        if(!tire[p][ch])
            tire[p][ch]=++ant;
            p=tire[p][ch];
    }
    cnt[p]++;
    //cout<<p<<" "<<cnt[p]<<endl;
}
//int srh(char *str)
//{
//    int ans=0;
//    int len=strlen(str);
//    int p=0;
//    for(int i=0;i<len;i++){
//        int ch=str[i]-'a';
//        p=tire[p][ch];
//        if(!p) return ans;
//        ans+=cnt[p];
//    }
//    return ans;
//}
int op;
void cal(int u)
{

    if(cnt[u]){
        op++;
        num[u]=op;
        return;
    }
    for(int i=0;i<26;i++){
        if(tire[u][i])
            cal(tire[u][i]);
    }
}
int main()
{
    init();
    ios::sync_with_stdio(false);
    cin.tie(0);
    while(cin>>n>>k){
        ant=0;
        memset(cnt,0,sizeof(cnt));
        memset(tire,0,sizeof(tire));
        memset(c,0,sizeof(c));
        memset(num,0,sizeof(num));
        for(int i=1;i<=n;i++){
            cin>>str;
            ins(str);
        }
        cin>>str;
        op=0;
        cal(0);
        ll ans=0;
        ll t;
          int x;
        int u=0,id=0;
        int len=strlen(str);
        for(int i=0;i<len;i++){
            t=str[i]-'a';
            u=tire[u][t];
            if(cnt[u]){
                id++;
                x=getsum(num[u]);
                ans=(ans+qmul(qmul((num[u]-1-x),f[n-id]),invf[n-k]))%mod;
                add(num[u],1);
                u=0;
            }
        }
        cout<<(ans+1)%mod<<endl;//%lxq
    }
    return 0;
}

比賽時瘋狂瞎改,想盡了所有加快的方法,加了tire之後跑得超快,直接第一.....

EXAM-2018-08-26