题解 P1666 【前缀单词】

· · 题解

引理:

把这些字符串排序后,对于任意一组j<i且他们不互为前缀,则对于任意一组k<j且他们不互为前缀,则ki不互为前缀。

证明:

ki互为前缀,则k的长度必然小于i,那么ik之间必然仅有以k为前缀的字符串,则k必然为j的前缀,矛盾。

这个证明与后缀数组求高度数组的O(n)算法的证明有点像

于是dp式就显而易见了。

代码如下: ```cpp #include <cstdio> #include <iostream> #include <algorithm> using namespace std; string s[55]; int n , f[55][55]; long long dp[55];//2^50次方在longlong以内 int Compare(int x , int y) { if(s[x].length() > s[y].length()) swap(x , y); for (unsigned i = 0; i < s[x].length(); ++i) { if(s[x][i] != s[y][i]) return 1; } return 0; } int main() { scanf("%d" , &n); for (int i = 1; i <= n; ++i) cin >> s[i] , dp[i] = 1;//输入与初始化 sort(s + 1 , s + 1 + n); long long ans = 1; for (int i = 2; i <= n; ++i) for (int j = i - 1; j >= 0; --j) if(Compare(i , j)) dp[i] += dp[j];//dp转移 for (int i = 1; i <= n; ++i) ans += dp[i];//统计答案 printf("%lld" , ans); return 0; } ```