BUNOJ--29355 手速为王

本文详细阐述了如何使用Trie树结构来高效地处理字符串输入和操作,包括正反两次添加字符串,计算总退格次数,并通过实例演示了算法实现过程。

把每个单词正反两次加到字典里,输入每一个单词,每次都会把它输成其他2*n-1个单词,再按退格修改。求总退格数。

http://www.bnuoj.com/bnuoj/problem_show.php?pid=29355

Trie树。先把字符串正反两次加到Trie树里。维护cnt[i], 表示i节点存储相同字母的单词的个数。

sum表示 在没有任何节点重合的情况下节点的总和,也就是长度之和。

在输入一个单词的时候,如果cnt[i] = k,那么在输入这个单词的时候在i节点就少退格k次,在这个节点一共有k个串满足这个要求,所以一共少退格k*k次

算出一共少退格多少次,再用sum减去这个值就是答案。

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MaxNode = 500000 + 10;
typedef long long ll;
int chd[MaxNode][26],  ID[128];
ll cnt[MaxNode], sz, sum;
char str[MaxNode];
int T, n;
void init(){
    memset(chd, 0, sizeof(chd));
    memset(cnt, 0, sizeof(cnt));
    sz = 1;
    sum = 0;
}
void Insert(char *s){
    int cur = 1;
    int len = strlen(s);
    sum += 2 * len;
    for(int i=0; i<len; i++){
        if(!chd[cur][ID[s[i]]])
            chd[cur][ID[s[i]]] = ++sz;
        cur = chd[cur][ID[s[i]]];
        cnt[cur]++;
    }
    cur = 1;
    for(int i=len-1; i>=0; i--){
        if(!chd[cur][ID[s[i]]])
            chd[cur][ID[s[i]]] = ++sz;
        cur = chd[cur][ID[s[i]]];
        cnt[cur]++;
    }
}
int main(){
    scanf("%d", &T);
    for(int i='a'; i<='z'; i++) ID[i] = i - 'a';
    while(T--){
        scanf("%d", &n);
        init();
        for(int i=0; i<n; i++){
            scanf("%s", str);
            Insert(str);
        }
        ll ans = 0;
        for(int i=2; i<=sz; i++){
            ans += cnt[i] *cnt[i];
        }
        printf("%lld\n", sum * 2 * (ll)n - ans);
    }
    return 0;
}



评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值