2022ICPC杭州K题 Master of Both
题目
给定n和m,表示n个字符串和m组询问
字符串长度1e5,总长度不超过1e6
m组询问中,每次给定一个字符串(只含有26个不同的小写字母),表示比较规则(前面小于后面),求n个字符串中的逆序对个数
性质
首先发现,对于n个字符串中任意两个字符串a,b,只有两种情况
做法
- 字典树
- 插入字符串的时候维护res数组和cnt数组。
- 设res[i][j]表示 字母i>字母j的情况下,产生的逆序对个数
- 设cnt数组表示字典树中节点i的字数中有多少个单词
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
| #include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=1e6+5; int t[N][26],idx; ll cnt[N]; ll res[26][26]; ll chushi; ll n,m;
void update_res(int p,int q){ for(int i=0;i<26;i++){ res[i][q]+=cnt[t[p][i]]; } }
void insert(const string &s){ int p=0; for(int i=0;i<s.size();i++){ int q=s[i]-'a'; if(!t[p][q])t[p][q]=++idx; update_res(p,q); p=t[p][q]; cnt[p]++; } for(int i=0;i<26;i++){ chushi+=cnt[t[p][i]]; } }
ll ask(const string &s){ ll ans=0; for(int i=0;i<s.size();i++){ for(int j=i+1;j<s.size();j++){ ans+=res[s[j]-'a'][s[i]-'a']; } } return ans; }
int main() { cin>>n>>m; for(int i=1;i<=n;i++){ string s; cin>>s; insert(s); } while(m--){ string s; cin>>s; cout<<ask(s)+chushi<<endl; } return 0; }
|