zoukankan      html  css  js  c++  java
  • 2021牛客多校10 Browser Games(压缩trie)

    银川K加强版,内存限制32M,字符串总长1e5*100,直接建出trie树dp很显然是会T的。
    dp的思路:每个串都对应一个叶子节点,每次都是以某个叶子为起点向上dp。每个节点的权值等于这棵子树还有多少个叶子节点(即这个点有多少个串经过),以这个为每个点的权值。按顺序从叶子节点开始删,每次先让ans++,然后沿着叶子向上删到不是叶子节点(并且不是根子节点的点),减掉这些点的dp值,最后在把最后删的点的父节点的dp值++。

    从上面这个dp的过程中可以发现,dp只需要记录开始的叶子节点,并不需要再去匹配,所以只需要树结构本身,而不需要每个点对应的字符;同时串之间会共用很多节点,如果把这些节点缩成一个点,空间占用就能很大程度的减小。

    那么我们可以把串按字典序排序,那些共用节点的串肯定有公共前缀,这些前缀的长度各不相同,可以分治建出树来dp。

    #include<bits/stdc++.h>
    #include<unordered_map>
    using namespace std;
    #define ll long long
    //#define double long double
    #define fastio ios::sync_with_stdio(false),cin.tie(NULL),cout.tie(NULL)
    #define pii pair<int,int>
    #define pll pair<ll,ll>
    const double PI = acos(-1);
    const int inf = 1e9;
    const ll lnf = 1e18 + 7;
    const int maxn = 3e5 + 10;
    const int N = 1 << 30 - 1;
    ll mod = 998244353;
    double eps = 1e-8;
    
    int fa[maxn];//父节点
    int dp[maxn];
    int v[maxn];//每个点的子树中有多少叶子
    int cnt = 0;
    
    char c[maxn][105];//串
    int id[maxn];//排序后的下标
    
    //分治建树
    void make_tree(int l, int r, int deep, int root)
    {
        //先对当前分治的区间[l,r]排序(它们[0,deep)的前缀相同)
        sort(id + l, id + r + 1, [&](int x, int y) {
            return c[x][deep] < c[y][deep];
            });
        int i = l, j = l;
        while (i <= r)
        {
            if (i + 1 > r || c[id[i]][deep] != c[id[i + 1]][deep])//找到一些c[deep]相同的串
            {
                //cout << now << endl;
                if (i == j)//如果只有1个串,那么它将会是叶子,直接建出来
                {
                    fa[id[i]] = root;
                    v[id[i]] = 1;
                    i++, j++;
                    continue;
                }
                //否则去看这些共c[deep]的串的c[deep+1]、c[deep+2]是否可以缩成1个点
                int nex = 1;
                while (1)
                {
                    bool ok = 1;
                    for (int k = j; ok && k < i; k++)
                        if (c[id[k]][deep + nex] != c[id[k + 1]][deep + nex])
                            ok = 0;
                    if (ok)
                        nex++;
                    else
                    {
                        ++cnt;
                        v[cnt] = i - j + 1;
                        fa[cnt] = root;
                        make_tree(j, i, deep + nex, cnt);
                        j = i + 1;
                        break;
                    }
                }
            }
            i++;
        }
    }
    
    int main()
    {
        int n;
        scanf("%d", &n);
        cnt = n;
        for (int i = 1; i <= n; i++)
            scanf("%s", c[i] + 1), id[i] = i;
        make_tree(1, n, 1, 0);
        int ans = 0;
        vector<int>dp(cnt + 1, 0);
        for (int x = 1; x <= n; x++)
        {
            int now = x, p = -1;
            while (now)
            {
                v[now]--;
                if (v[now] == 0)
                    p = now, ans -= dp[now];
                now = fa[now];
            }
            dp[fa[p]]++;
            ans++;
            printf("%d
    ", ans);
        }
        return 0;
    
    }
    
  • 相关阅读:
    linux 遇到(vsftpd)—500 OOPS:chroot
    linux中配置JAVA环境
    win主机ping不通linux的IP
    java:递归算法
    MySQL数据库中字段类型为tinyint,读取出来为true/false的问题
    Mybaitis-generator生成数据对象和时间的优化
    IntelliJ IDEA 2017.1.6 x64 的破解
    在eclipse中maven构建Web项目,tomcat插件在maven中的运用
    Maven 的聚合
    理解面向对象
  • 原文地址:https://www.cnblogs.com/ruanbaiQAQ/p/15158026.html
Copyright © 2011-2022 走看看