dp[i]代表前i个字符组成的串中所有前缀出现的次数。
dp[i] = dp[next[i]] + 1;
因为next函数的含义是str[1]~str[ next[i] ]等于str[ len-next[i]+1 ]~str[len],即串的前缀后缀中最长的公共长度。
对于串ababa,所有前缀为:a, ab,aba,abab, ababa, dp[3] = 3;
到达dp[5]的时候,next = 3, 它与前面的最长公共前缀为aba,因此dp[5]的凑法应该加上dp[3],再+1是加上ababa它本身。
说不太清楚……从感觉上比较类似于那个“给你几种面值的硬币,问凑出指定钱数的所有凑法”的dp方式。
#include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> using namespace std; const int MAXN = 200100; const int MOD = 10007; int len; char str[MAXN]; int nextval[MAXN]; int dp[MAXN]; void getNext(char s[],int next[]) { int length=len; int i=0,j=-1; next[0]=-1; while(i<length) { if(j==-1||s[i]==s[j]) { ++i; ++j; next[i]=j; } else j=next[j]; } } int main() { int T; scanf( "%d", &T ); while ( T-- ) { scanf( "%d", &len ); scanf( "%s", str ); getNext( str, nextval ); int ans = 0; memset( dp, 0, sizeof(dp) ); for ( int i = 1; i <= len; ++i ) { dp[i] += ( dp[ nextval[i] ] + 1 )%MOD; ans += dp[i]; ans %= MOD; } printf( "%d ", ans % MOD ); } return 0; }