QvQ终于搞出来的,条件判断略多
题意是:给出n个字符,用strcmp()来对它们两两这间相互比较,求要比较总次数
n在[1~4000]之间
strcmp()的比较方法很有意思,会对两个字符串对应位置进行比较,如果相同再比较是否为'/0',所以对于“a”和"a"这两上字符串,要比较4次
第一次,比较'a'和'a',发现它们相同,再看‘a'是否等于'\0',不等于,继续比较,到目前为止,比较了两次
第二次,比较’/0'和'/0',发现它们相同,再看是否为'\0',等于,结束比较,直接返回
如果第一次比较就不相同,直接返回
从数据量来看,要用trie树来优化,我的方法是边建树边计算,那么读完所有数据的时间,就能出答案了XD
用u来表示父节点,c为当前的字符,ch[u][c]则用来存其子节点的序号,令cid=ch[u][c];
要开以下几个数组,layer[]用来保存当前字符在树中的第几层,sons[]表示当前节点有几个子节(包括其自己),ends[]表示有多不和个字符串走到当前节点时停止,即相同的字符串数。
(1)当未到达最后一层时
考虑同一层里,与它不相同的字符串
当走到ch[u][c]时,在当前层,与c不相同的字符串一共有sons[u]-sons[cid]个
比如
abcd
abef
当第二串走到第三层时,字符为e, 有一个字符串abcd与它不同,这时,sons[u]为2,sons[cid]=1。。。
比较次数为2*layer[u]+1;
(2)当到达最后一层时
为什么这里要单独说呢=w=因为从1看出,有的计算要用到其父节点,但是最后一层是没有的,额外考虑
答案直接为ans+=(sons[cid]-1)*(2*layer[cid]+1)+ends[cid];
即为其所有子结点(不包括自己)判断次数,再加上到当前节点为止的ends的数目
其实原来应该为ans+=(sons[cid]-1-ends[cid]*(2*layer[cid]+1)+ends[cid]*(2*layer[cid]));
这是因为,对于其它子节点,比如aa和a, 要比较3次,而和a一样在父节点就终结的,要比较4次,
把第二个式整理一下就是第一个了。
以上,就出来了>.<
但是由于UVa不知为何总是submission error,我随便找了个标程,再成了几百组数据,这些测过是没问题的。不知会不会有还没考虑的trick……
(边写边发现原程序的bug…贴出来的和原来,核心部分都改了好多……QAQ,但下面这个过了测试数据了XD,pretest passed)
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cctype>
#include<string>
#include<iostream>
using namespace std;
const int maxnode=4000*1000+100;
const int sigma_size=10+26*2;
struct Trie
{
int ch[maxnode][sigma_size];
int layer[maxnode];
int ends[maxnode];
int sons[maxnode];
int val[maxnode];
int sz, ans;
void init()
{
sz=1;ans=0;
memset(val, 0, sizeof(val));
memset(ends, 0, sizeof(ends));
memset(ch[0], 0, sizeof(ch[0]));
memset(layer, 0, sizeof(layer));
memset(sons, 0, sizeof(sons));
}
int idx(char x)
{
if(isdigit(x))return x-'0';
else if(islower(x))return x-'a'+10;
else if(isupper(x))return x-'A'+36;
}
void insert(string &s, int v)
{
sons[0]++;
int u=0, n=s.size();
for(int i=0;i<n;i++)
{
int c=idx(s[i]);
if(!ch[u][c])
{
memset(ch[sz], 0, sizeof(ch[sz]));
val[sz]=0;
ch[u][c]=sz++;
}
int cid=ch[u][c];
layer[cid]=layer[u]+1;
sons[cid]++;
ans+=(sons[u]-sons[cid])*(2*layer[u]+1);
if(i==n-1)ans+=(sons[cid]-1)*(2*layer[cid]+1)+ends[cid];
u=cid;
}
val[u]=v;
ends[u]++;
}
}trie;
int main()
{
int n;
int cnt=0;
string str;
while(~scanf("%d", &n), n)
{
cnt++;
trie.init();
for(int i=0;i<n;i++)
{
str.clear();
cin>>str;
trie.insert(str, 1);
//cout<<trie.ans<<endl;
}
printf("Case %d: %d\n", cnt, trie.ans);
}
return 0;
}