BZOJ1174 - Toponyms(trie)

题意

给你一个字符集合,你从其中找出一些字符串出来. 希望你找出来的这些字符串的最长公共前缀*字符串的总个数最大化.

思路

先建好trie树,然后dfs预处理每个子树下单词个数,同时计算最大值即可。

但是因为数据很大,字符可能的种类很多,要用tr树要用邻接表实现。实测vector也不行。

#include <bits/stdc++.h>

#define endl '\n'
#define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define FILE freopen(".//data_generator//in.txt","r",stdin),freopen("res.txt","w",stdout)
#define FI freopen(".//data_generator//in.txt","r",stdin)
#define FO freopen("res.txt","w",stdout)
#define pb push_back
#define mp make_pair
#define seteps(N) fixed << setprecision(N) 
typedef long long ll;

using namespace std;
/*-----------------------------------------------------------------*/

ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
#define INF 0x3f3f3f3f

const int N = 5e6 + 10;
const double eps = 1e-5;

struct node {
    char p;
    int nt, ne;
};

int head[N];
node tr[N];
bool flag[N];
string s;
int si;
int ct;
ll ans;

void insert(const char str[]) {
    int cur = 0;
    for(int i = 0; str[i]; i++) {
        bool found = false;
        char p = str[i];
        for(int e = head[cur]; e; e = tr[e].ne) {
            if(tr[e].p == p) {
                cur = tr[e].nt;
                found = true;
                break;
            }
        }
        if(!found) {
            tr[++si] = node {p, ++ct, head[cur]};
            head[cur] = si;
            cur = ct;
        }
    }
    flag[cur] = 1;
}

int dfs(int cur, int dep) {
    int cnt = flag[cur];
    for(int e = head[cur]; e; e = tr[e].ne) {
        cnt += dfs(tr[e].nt, dep + 1);
    }
    ans = max(ans, 1ll * dep * cnt);
    return cnt;
}

int main() {
    //FI;
    IOS;
    int n;
    cin >> n;
    cin.ignore();
    for(int i = 1; i <= n; i++) {
        getline(cin, s);
        insert(s.c_str());
    }
    dfs(0, 0);
    cout << ans << endl;
} 
posted @ 2020-08-13 21:51  limil  阅读(129)  评论(0编辑  收藏  举报