51nod1464(trie + dfs)

题目链接: http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1464

题意: 中文题诶~

思路: 将所有半回文串构建成一棵字典树, 再 dfs 里面字典序第 k 大的字符串.

注意插入半回文串时不能完全暴力插入, 不然插入的时间复杂度为 O(n^3), 会 tle. 可以先用 dp 预处理一下, dp[i][j] 存储 子串[i, j] 是否为回文串, vis[i] 记录以 i 开头的最长半回文串末尾位置. 那么插入时可以每次插入 [i, vis[i]] 之间的所有半回文串, 时间复杂度为 O(n^2). 然后再 dfs 一下答案即可.

代码:

 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <string.h>
 4 using namespace std;
 5 
 6 const int MAXN = 5e3 + 10;
 7 int trie[MAXN * MAXN][2], num[MAXN * MAXN], id = 1;
 8 bool dp[MAXN][MAXN];//dp[i][j]存储[i,j] 是否为半回文串
 9 int vis[MAXN];//vis[i]存储以i开始的最长半回文串末尾位置
10 char s[MAXN];
11 
12 void init(int len){
13     for(int i = len - 1; i >= 0; i--){
14         vis[i] = i;
15         dp[i][i] = true;
16         for(int j = i + 1; j < len; j++){
17             if(s[i] == s[j]){
18                 if(i + 2 >= j - 2) dp[i][j] = true;
19                 else dp[i][j] = dp[i + 2][j - 2];
20             }
21             if(dp[i][j]) vis[i] = j;
22         }
23     }
24 }
25 
26 void insert(int st){
27     int node = 0;
28     for(int i = st; i <= vis[st]; i++){
29         int cnt = s[i] - 'a';
30         if(!trie[node][cnt]) trie[node][cnt] = id++;
31         if(dp[st][i]) num[trie[node][cnt]]++;
32         node = trie[node][cnt];
33     }
34 }
35 
36 int k;
37 string sol;
38 
39 void dfs(int x){
40     string cnt = sol;
41     if(k > 0 && trie[x][0]){
42         sol += 'a';
43         k -= num[trie[x][0]];
44         dfs(trie[x][0]);
45     }
46     if(k > 0 && trie[x][1]){
47         sol = cnt;
48         sol += 'b';
49         k -= num[trie[x][1]];
50         dfs(trie[x][1]);
51     }
52 }
53 
54 int main(void){
55     scanf("%s%d", s, &k);
56     int len = strlen(s);
57     init(len);
58     for(int i = 0; i < len; i++){
59         insert(i);
60     }
61     dfs(0);
62     cout << sol << endl;
63     return 0;
64 }
View Code
原文地址:https://www.cnblogs.com/geloutingyu/p/7672490.html