思路
有点麻烦的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;
}