http://acm.hdu.edu.cn/showproblem.php?pid=3336
题意:给定一个长度为n的字符串(0<n<20000),以n的前k个字符组成一个前序(k = 1,2,3,4.....n),在n中找与前序相同的子序列的个数。
所谓的记忆化搜索,是因为前一次的搜索对后面的搜索有帮助,就记录下来,这样可以减少后面搜索的时间。
看看样例:
abab
前序是 a,ab,aba,abab
建立一个num数组,记录每一个与前序相同的字串的头下标。
a | b | a | b | |
a | 0 | 2 | ||
ab | 0 | 2 | ||
aba | 0 | |||
abab | 0 |
num[0] | num[1] | num[2] | num[3] | |
a | 0 | 2 | ||
ab | 0 | 2 | ||
aba | 0 | |||
abab | 0 |
因为只有想要与一个前序相同,必先要与上一个前序相同,所以每次只要比较前序最后的一个元素是否与下标为num[k]加上前序长度的元素相同就可以了。
#include <stdio.h>
int main ()
{
int t,n,i,j,k,sum,all,len;//len是记录前序长度的
char ch[200010],ch1,ch2;
int num[200020],nn;//nn是记录num数组中元素的个数,每比较完一次元素就更新一次
scanf ("%d",&t);
while (t-- > 0)
{
len = 0;
scanf ("%d%c",&n,&ch2);
gets(ch);
for (i = 0 ; i < n ; i ++)
num[i] = i ;
nn = n;
sum = 0;
for (i = 0 ; i < n ; i ++)
{
ch1 = ch[i];
int ji = 0;
for (j = 0 ; j < nn ; j ++)
{
if (num[j] + len < n && ch1 == ch[num[j] + len] && num[j] + len < n)
{
sum ++;
sum = sum % 10007 ;
num[ji ++] = num[j];
}
}
nn = ji;
len ++;
}
printf ("%d\n",sum);
}
}