UVA11732 "strcmp()" Anyone?

思路

有点麻烦的Trie树题

注意到每个节点的贡献是(深度(根的深度是0)乘2+1)乘上在这个点分叉的字符串个数,所以全部插入之后dfs一遍即可(为了避免两个字符串一样的情况,还应该特判一下最后的中止节点)

代码

字符集太大需要用邻接表存才能跑过

直接存边的TLE代码

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <set>
#define int long long
using namespace std;
signed Trie[4000100][65];
int Nodecnt,sz[4000100],ans=0,root,n;
char s[4010][1010];
int tonum(char c){
    if(c>='a'&&c<='z')
        return c-'a';
    else if(c=='a'+26)
        return 26;
    else if(c>='A'&&c<='Z')
        return c-'A'+27;
    else if(c>='0'&&c<='9')
        return c-'0'+54;
}
void insert(char *s,int len){
    int o=root;
    sz[o]++;
    for(int i=0;i<len;i++){
        if(!Trie[o][tonum(s[i])])
            Trie[o][tonum(s[i])]=++Nodecnt;
        o=Trie[o][tonum(s[i])];
        sz[o]++;
    }
}
void dfs(int o,int dep,int isend=0){
    if(!isend){
        int midt=0;
        for(int i=0;i<65;i++){
            if(Trie[o][i]){
                sz[o]-=sz[Trie[o][i]];
                midt+=sz[Trie[o][i]]*sz[o];
            }
        }
        ans+=(dep+1)*midt;
        for(int i=0;i<65;i++){
            if(Trie[o][i]){
                dfs(Trie[o][i],dep+2,(i==26));
            }
        }
    }
    else{
        ans+=(sz[o]-1)*(sz[o])/2*dep;
    }
}
void init(void){
    for(int i=0;i<=Nodecnt;i++){
        for(int j=0;j<65;j++)
            Trie[i][j]=0;
        sz[i]=0;
    }
    ans=0;
    Nodecnt=1;
    root=1;
}
signed main(){
    // freopen("test.in","r",stdin);
    // freopen("test.out","w",stdout);
    Nodecnt=1;
    root=1;
    ans=0;
    int cnt=0;
    while(scanf("%lld",&n)==1&&n){
        ++cnt;
        for(int i=1;i<=n;i++){
            scanf("%s",s[i]+1);
            int len=strlen(s[i]+1);
            s[i][len+1]='a'+26;
            insert(s[i]+1,len+1);
        }
        dfs(root,0);
        printf("Case %lld: %lld
",cnt,ans);
        init();
    }
    return 0;
}

邻接表存边的AC代码

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <set>
#define int long long
using namespace std;
signed fir[4000100],nxt[4000100],v[4000100],num[4000100],Ecnt=0;
int Nodecnt,sz[4000100],ans=0,root,n;
char s[4010][1010];
int tonum(char c){
    if(c>='a'&&c<='z')
        return c-'a';
    else if(c=='a'+26)
        return 26;
    else if(c>='A'&&c<='Z')
        return c-'A'+27;
    else if(c>='0'&&c<='9')
        return c-'0'+54;
}
void addedge(int ui,int vi){
    ++Ecnt;
    v[Ecnt]=vi;
    nxt[Ecnt]=fir[ui];
    fir[ui]=Ecnt;
}
void insert(char *s,int len){
    int o=root;
    sz[o]++;
    for(int i=0;i<len;i++){
        int vx;
        bool f=false;
        for(int j=fir[o];j;j=nxt[j])
            if(num[v[j]]==tonum(s[i])){
                vx=v[j];
                f=true;
                break;
            }
        if(!f){
            vx=++Nodecnt;
            num[vx]=tonum(s[i]);
            addedge(o,vx);
        }
        o=vx;
        sz[o]++;
    }
}
void dfs(int o,int dep,int isend=0){
    if(!isend){
        int midt=0;
        for(int i=fir[o];i;i=nxt[i]){
            sz[o]-=sz[v[i]];
            midt+=sz[v[i]]*sz[o];
        }
        ans+=(dep+1)*midt;
        for(int i=fir[o];i;i=nxt[i]){
            dfs(v[i],dep+2,(num[v[i]]==26));
        }
    }
    else{
        ans+=(sz[o]-1)*(sz[o])/2*dep;
    }
}
void init(void){
    ans=0;
    Nodecnt=1;
    root=1;
    Ecnt=0;
    memset(sz,0,sizeof(sz));
    memset(fir,0,sizeof(fir));
    memset(nxt,0,sizeof(nxt));
    memset(v,0,sizeof(v));
    memset(num,0,sizeof(num));
}
signed main(){
    // freopen("test.in","r",stdin);
    // freopen("test.out","w",stdout);
    Nodecnt=1;
    root=1;
    ans=0;
    int cnt=0;
    while(scanf("%lld",&n)==1&&n){
        ++cnt;
        for(int i=1;i<=n;i++){
            scanf("%s",s[i]+1);
            int len=strlen(s[i]+1);
            s[i][len+1]='a'+26;
            insert(s[i]+1,len+1);
        }
        dfs(root,0);
        printf("Case %lld: %lld
",cnt,ans);
        init();
    }
    return 0;
}