zoukankan      html  css  js  c++  java
  • BNU OJ 29355 手速为王

    题目链接:http://www.bnuoj.com/bnuoj/problem_show.php?pid=29355

    与Trie树相关的计数问题。

    因为正反各插了一次,所以字典中一共有2N个单词。

    val[i]存储了在该位置有相同字母的单词的个数,对于在该位置的每个字母,2N-val[i]代表与其不同的单词个数,所以对于每个单词的每个位置的字母,不同的需要删,相同的不需要删。对于在该位置的所有单词,一共删的次数即为val[i]*( 2*N - val[i] )。

    把每个位置都跑一边,最后的式子即为:ans += val[i]*( 2*N - val[i] )

    这个方法也是从别人的代码里学来的,我能力有限,说不太清楚,请在式子中自己体会=3=

    个人感觉这个计数方法很不错,我自己想想不出来。。。

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <cstdlib>
     4 
     5 #define LL long long int
     6 
     7 const int MAXSIZE = 200100;
     8 const int sigma_size = 26;
     9 
    10 struct Trie
    11 {
    12     int val[MAXSIZE];
    13     int ch[MAXSIZE][sigma_size];
    14     int sz;
    15 
    16     void init()
    17     {
    18         memset( val, 0, sizeof(val) );
    19         memset( ch[0], 0, sizeof(ch[0]) );
    20         sz = 1;
    21         return;
    22     }
    23 
    24     inline int idx( char cc )
    25     {
    26         return cc - 'a';
    27     }
    28 
    29     void InsertStr( char *s )
    30     {
    31         int len = strlen(s);
    32 
    33         int u = 0;
    34         for ( int i = 0; i < len; ++i )
    35         {
    36             int c = idx( s[i] );
    37             if ( !ch[u][c] )
    38             {
    39                 memset( ch[sz], 0, sizeof(ch[sz]) );
    40                 ch[u][c] = sz++;
    41             }
    42             u = ch[u][c];
    43             ++val[u];
    44         }
    45 
    46         u = 0;
    47         for ( int i = len - 1; i >= 0; --i )
    48         {
    49             int c = idx( s[i] );
    50             if ( !ch[u][c] )
    51             {
    52                 memset( ch[sz], 0, sizeof(ch[sz]) );
    53                 ch[u][c] = sz++;
    54             }
    55             u = ch[u][c];
    56             ++val[u];
    57         }
    58         return;
    59     }
    60 };
    61 
    62 Trie tr;
    63 char str[MAXSIZE];
    64 
    65 int main()
    66 {
    67     int T;
    68     scanf( "%d", &T );
    69     while ( T-- )
    70     {
    71         tr.init();
    72 
    73         int N;
    74         scanf( "%d", &N );
    75         for ( int i = 0; i < N; ++i )
    76         {
    77             scanf( "%s", str );
    78             tr.InsertStr( str );
    79         }
    80 
    81         LL ans = 0;
    82         for ( int i = 1; i <= tr.sz; ++i )
    83             ans += tr.val[i] * ( N + N - tr.val[i] );
    84 
    85         printf( "%lld\n", ans );
    86     }
    87     return 0;
    88 }

    我能说这题的精华就是这一句ans += tr.val[i] * ( N + N - tr.val[i] )么……TAT……只要能想清楚这点,这题就很简单了。

    最后想吐槽下自己:刚在赛场上看见这题的时候眼前一亮——哦哦哦Trieeeeee~~~终于找到一个我会的数据结构……OTL

    然后一想计数问题就傻了,半天没搞明白。一直纠结于前缀有重叠,计数如何才能不重不漏云云……

    单会数据结构,思路转化不来又有什么用……说到底还是跟不会一样……

  • 相关阅读:
    C#-获取磁盘,cpu,内存信息
    C#-WiFi共享
    C#-WiFi共享
    C#-DES加解密
    C#-DES加解密
    C#-播放器相关
    C#-播放器相关
    Windowsw核心编程 第13章 Windows内存结构
    Windowsw核心编程 第13章 Windows内存结构
    C#-CHTTPDownload
  • 原文地址:https://www.cnblogs.com/GBRgbr/p/3058456.html
Copyright © 2011-2022 走看看