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 }

 

posted @ 2017-03-17 21:24  _yxg123  阅读(134)  评论(0编辑  收藏  举报