CF 965E Short Code 贪心 字典树 启发式合并

题意:

给你N个字符串,每个字符串可以缩写为他的前缀,但是必须保证所有串缩写后不重复,并且最后总长度最小。

题解:

先建立字典树,然后我们可以想到,在dfs的时候,如果当前节点本来没有串,那么他可以存他子树中某个串,我们用优先队列找到他子树的最长的节点,然后把这个节点代表的串用当前节点串代替,这样贪心即可。

但是对于每颗子树都要建立一个优先队列存他子树中所有的串长。对于这点我们可以用启发式合并来做。

代码:

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
#include <bitset>
#include <map>
#include <vector>
#include <stack>
#include <set>
#include <cmath>
#ifdef LOCAL
#define debug(x) cout<<#x<<" = "<<(x)<<endl;
#else
#define debug(x) 1;
#endif

#define chmax(x,y) x=max(x,y)
#define chmin(x,y) x=min(x,y)
#define lson id<<1,l,mid
#define rson id<<1|1,mid+1,r
#define lowbit(x) x&-x
#define mp make_pair
#define pb push_back
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, int> pii;

const ll MOD = 1e9 + 7;
const double eps = 1e-10;
const int INF = 0x3f3f3f3f;
const ll INFLL = 0x3f3f3f3f3f3f3f3fll;
const int MAXN = 1e5 + 5;

priority_queue<int> q[MAXN];

struct nodes {
    int nxt[26], v, dep;
} nd[MAXN];
int tot;

void add (char *s) {
    int now = 0;
    for (int i = 0; s[i]; i++) {
        int id = s[i] - 'a';
        if (!nd[now].nxt[id]) {
            nd[now].nxt[id] = ++tot;
            nd[tot].dep = i + 1;
        }
        now = nd[now].nxt[id];
    }
    nd[now].v = 1;
}

char s[MAXN];
int ans;
int tran[MAXN];

void dfs (int now) {
    tran[now] = now;
    for (int i = 0; i < 26; i++) {
        int nxt = nd[now].nxt[i];
        if (!nxt) continue;
        dfs (nxt);
        if(q[tran[now]].size() > q[tran[nxt]].size()) {
            while(q[tran[nxt]].size()) q[tran[now]].push(q[tran[nxt]].top()), q[tran[nxt]].pop();
        } else {
            while(q[tran[now]].size()) q[tran[nxt]].push(q[tran[now]].top()), q[tran[now]].pop();
            tran[now] = tran[nxt];
        }
    }
    if (nd[now].v) {
        ans += nd[now].dep;
        q[tran[now]].push(nd[now].dep);
    } else if (now) {
        ans += nd[now].dep - q[tran[now]].top();
        q[tran[now]].pop();
        q[tran[now]].push(nd[now].dep);
    }
}

int main() {
#ifdef LOCAL
    freopen ("input.txt", "r", stdin);
#endif
    int n;
    scanf ("%d", &n);
    for (int i = 1; i <= n; i++) {
        scanf ("%s", s);
        add (s);
    }
    dfs(0);

    printf("%d\n", ans);
    return 0;
}

后记:

不知道为什么,不用启发式也可以过,而且跑得还快一些。

但是我估计的复杂度是N^2logN。

启发式合并的话是NlogNlogN。

猜你喜欢

转载自blog.csdn.net/c6376315qqso/article/details/82468638
今日推荐