Wannafly 每日一题 2016-12-26 KAOS 字典树
题目链接:
http://www.spoj.com/problems/KAOS/
题意:
给定n个字符串,统计字符串(s1, s2)的对数,使得s1的字典序比s2的字典序要大,s1反一反(abc==>cba,记为s1’)比s2’的字典序要小。
题解:
按字符串的字典序排序,从小到大枚举,假设现在考虑到了字符串s1,那么我们已经处理过了所有字典序小于s1的字符串s2,我们关心的是这些字符串中满足s1’小于s2’的s2的数目。Ok,这个task可以完美地用trie树解决。
代码:
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 #define MS(a) memset(a,0,sizeof(a)) 5 #define MP make_pair 6 #define PB push_back 7 const int INF = 0x3f3f3f3f; 8 const ll INFLL = 0x3f3f3f3f3f3f3f3fLL; 9 inline ll read(){ 10 ll x=0,f=1;char ch=getchar(); 11 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 12 while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} 13 return x*f; 14 } 15 ////////////////////////////////////////////////////////////////////////// 16 const int maxn = 1e6+10; 17 18 string str[maxn]; 19 int a[maxn][30],f[maxn]; 20 int cnt; 21 22 void insert(string s){ 23 int len = s.size(); 24 int now = 0; 25 for(int i=len-1; i>=0; i--){ 26 if(!a[now][s[i]-'a']) 27 a[now][s[i]-'a'] = ++cnt; 28 now = a[now][s[i]-'a']; // 爬到下一层 29 ++f[now]; 30 } 31 } 32 33 ll calc(string s){ 34 int len = s.size(),now=0; 35 ll ans = 0; 36 for(int i=len-1; i>=0; i--){ 37 for(int j=s[i]-'a'+1; j<26; j++) 38 ans += f[a[now][j]]; // 每一层的贡献就是比当前串字典序大的字符串 39 now = a[now][s[i]-'a']; 40 } 41 42 for(int i=0; i<26; i++) 43 ans += f[a[now][i]]; 44 return ans; 45 } 46 47 int main(){ 48 int n; 49 cin >> n; 50 for(int i=0; i<n; i++) 51 cin >> str[i]; 52 sort(str,str+n); 53 54 ll ans = 0; 55 for(int i=0; i<n; i++){ 56 insert(str[i]); 57 ans += calc(str[i]); 58 } 59 60 cout << ans << endl; 61 62 return 0; 63 }