集训 0619
T1:
一道字符串题目,给定一个字符串集合,求有多少个字符串可以被表示成A前缀+B前缀的形式。
关键在于去重。定义合法状态上加上一维表示B的前缀不能可以切掉接到A的后面去。
那么问题转化成有多少个子串满足前缀可以被接到另外的字符串后面,且切掉这个前缀后剩下的后缀同样是Trie树上的前缀。
那么,考虑一下如何求这玩意,
前缀可以被接到另外的字符串后面,意味着这在FAIL树上它是那些字符串的前缀,可以利用FAIL树的siz域求。
考虑剩下的后缀同样是Trie上的前缀,那么意味着从这个点往上跳FAIL树可以跳到这个后缀字符串。
再考虑发现若一个前缀被重复接上了,那么只要最小的前缀可以接上,较大的前缀也可以。(总感觉有歧义)。
那么只需要统计最小的前缀FAIL树上的siz域-1即可。
具体的实现就是
1 int id[maxn]; 2 void DFS(int x){ 3 id[len[x]]=x; 4 if(f[x])ans-=siz[id[len[x]-len[f[x]]]]-1; 5 for(int i=0;i<26;i++) 6 if(c[x][i])DFS(c[x][i]); 7 }
了解我的人应该都知道是什么意思吧.....应该吧。
T2:
一种很妙但没有什么拓展性的DP做法和一个很难写但拓展性较强的点分做法。
嗯,我再看看...
T3:
HALL定理,我要看看。