• UVA


    UVA - 11732

    这几天到处赠饭领红包,感觉脸都笑得僵硬了。。。在家好没状态,还是早点去学校算了*_*

    题意: 输入n个字符串(有大小写字母和数字),两两调用一次strcmp(),一共调用 n*(n+1) 次,问字符比较的总次数是多少?

    int strcmp(char *s, char *t)
    {
        int i;
        for (i=0; s[i]==t[i]; i++)
            if (s[i]=='')
                return 0;
        return s[i] - t[i];
    }

    注 :s[i]==t[i] 和 s[i]=='' 各有一次比校。

    tags:明显的字典树,边插入边统计就好了

    #include<bits/stdc++.h>
    using namespace std;
    #pragma comment(linker, "/STACK:102400000,102400000")
    #define rep(i,a,b) for (int i=a; i<=b; ++i)
    #define per(i,b,a) for (int i=b; i>=a; --i)
    #define mes(a,b)  memset(a,b,sizeof(a))
    #define INF 0x3f3f3f3f
    #define MP make_pair
    #define PB push_back
    #define fi  first
    #define se  second
    typedef long long LL;
    
    const int N = 5000005;
    struct Trie
    {
        char ch[N];
        int sz, son[N], bro[N];
        int tot[N];
        void Init()
        {
            sz=son[0]=bro[0]=tot[0]=0;
        }
        LL  Insert(char* str)
        {
            LL  ret = 0;
            ++tot[0];
            int len=strlen(str), u=0, to;
            for(int i=0; i<=len; ++i)
            {
                for(to=son[u]; to; to=bro[to])
                    if(ch[to]==str[i]) break;
                if(to==0)
                {
                    to=++sz;  tot[to]=0;
                    son[to]=0, ch[to]=str[i];
                    bro[to]=son[u], son[u]=to;
                }
                else
                {
                    ret += 1LL*tot[to]*2;  ///
                }
                ++tot[to];
                ret += tot[u]-tot[to];   ///
                u = to;
            }
            return ret;
        }
    } trie;
    
    char si[1005];
    int main()
    {
        int cas = 0, n;
        while(~scanf("%d", &n) && n)
        {
            trie.Init();
            LL ans = 0;
            rep(i,1,n) {
                scanf("%s", si);
                ans += trie.Insert(si);
            }
            printf("Case %d: %lld
    ", ++cas, ans);
        }
    
        return 0;
    }
    /*
    3
    that
    than
    thae
    2
    there
    the
    */
    View Code

    一般的字典树题目,我们习惯用双数组解决。但是当字符集很大的时候用双数组的形式很有可能会超内存,这个时候就要用 左儿子右兄弟 的形式储存 trie 树。左儿子右兄弟的形式可以有效地节约内存,而且初始化很快,但是插入和询问是 O(n*log(n)), 算是以时间换取空间。

    Trie 左儿子右兄第模板:

    // Trie 左儿子右兄弟模板
    const int N = 5000005;
    struct Trie
    {
        char ch[N];// ch[i]为第i个结点上的字符
        int sz, son[N], bro[N];  // 结点总数、左儿子编号、右兄弟编号
        int tot[N];   // tot[i]为第i个结点为根的子树包含的叶子结点总数
        void Init()
        {
            sz=son[0]=bro[0]=tot[0]=0;
        }
        void  Insert(char* str)
        {
            ++tot[0];
            int len=strlen(str), u=0, to;
            for(int i=0; i<len; ++i)
            {
                for(to=son[u]; to; to=bro[to])
                    if(ch[to]==str[i]) break;
                if(to==0)  // 没有找到就新建结点
                {
                    to=++sz,   tot[to]=0;
                    son[to]=0, ch[to]=str[i];
                    bro[to]=son[u], son[u]=to;  //插入进去
                }
                ++tot[to];
                u = to;
            }
        }
    } trie;
  • 相关阅读:
    我喜欢的女孩有了男友 :(
    两个月后,我又回来了。
    准备辞职,想看看老板知道我要辞职之后的表情。
    已经交了辞职报告,今天下午跟老板谈一谈。
    上班第十天
    一年了,回来看看。
    上班第十一天
    领到了离职通知单
    对上班失去了兴趣
    还没有拿到回家的火车票,惨了啊。
  • 原文地址:https://www.cnblogs.com/sbfhy/p/8459823.html
Copyright © 2020-2023  润新知