prefixfreecode—E
阿新 • • 發佈:2018-12-18
連結:
題意:
給出 n個字串,從中選出m個排列,問這m個字元構成的串在所有選出m個字元的排列中排第幾。(類似康拓展開)
思路:
字串排序,構造字典樹並對每個單詞標號,然後得到構成串的序列號,利用樹狀陣列維護序列中某個位置的數後面有幾個比他小的數。
#include <bits/stdc++.h> using namespace std; typedef long long ll; const ll mod = 1e9 + 7; const int maxn = 1e6 +1000; struct Node { bool judge;//是否是單詞結尾點 int next[26]; int index; //單詞編號,按字典序排序後的 } node[maxn]; int n,m,root,tot; ll ans[maxn],c[maxn],sum;//ans:階乘數,c:樹狀陣列的c陣列 int ID() { node[tot].judge = false; memset(node[tot].next,-1,sizeof (node[tot].next)); node[tot].index = 0; return tot++; } int lowbit(int x) { return x&(-x); } ll getSum(int x) { ll Sum = 0; for(int i = x; i; i-= lowbit(i)) { Sum += c[i]; } return Sum; } void addSum(int x,int val) { for(int i = x + 1; i <= n; i += lowbit(i))//這裡是從x+1開始更新的,感覺x也行 c[i]+=val; } void BuildTree(int r,string s,int id) { int len = s.size(); for(int i = 0; i < len; i++) { int num = s[i] - 'a'; if(node[r].next[num] == -1) { node[r].next[num] = ID(); } r = node[r].next[num]; } node[r].judge = true; node[r].index = id; } void init()//初始化操作 { tot = sum = 0; ans[m] = 1; ll res = (n - m + 1) % mod; for(int j = m - 1; j >= 1; j--) { ans[j] = (ans[j+1] * res) % mod; res = (res + 1) % mod; } memset(c,0,sizeof c); for(int i = 1 ; i <=n ; i++) { addSum(i,1); } } void searchTree(int r,string s) { int len = s.size(); int pos = 1; for(int i = 0 ; i < len; i++) { int num = s[i] - 'a'; r = node[r].next[num]; if(node[r].judge) { int k = node[r].index; sum += (ans[pos] * getSum(k)) % mod; addSum(k,-1); pos++; r = root; } } } int main() { ios::sync_with_stdio(false); vector<string> v; string ss; cin>>n>>m; init(); root = ID(); for(int i = 0; i < n; i++) { cin>>ss; v.push_back(ss); } sort(v.begin(),v.end()); for(int j = 0; j < v.size(); j++) { BuildTree(root,v[j],j+1); } cin>>ss; searchTree(root,ss); cout<<(sum+1)%mod<<endl; return 0; }