http://acm.hdu.edu.cn/showproblem.php?pid=3336
解题报告:刚开始用的是暴力的方法,就是每次往next数组中加一个元素,然后再在整个数组中进行查找,虽然加了很多的优化,但是还是无限的TLE中。(拒绝暴力,另寻他路)。
直接用next数组的意义,不过这次的求解next的方法与上次有些不同,暂且叫作方法二吧:
void get_next() { int i=0,j=-1; next[0]=-1; while(i<n) { while(j>-1&&a[j]!=a[i]) { j=next[j]; } i++; j++; next[i]=j; printf("next[%d]=%d\n",i,next[i]); } }
与原来的算法有什么不同呢?虽然也定义next[0]=-1,但后面绝不会出现-1,除了next[0],其他模式值next[j]=k(0≤k<j)的意义可以简单看成是:下标为j的字符的前面最多k个字符与开始的k个字符相同,这里并不要求a[j]!=a[k]。其实next[0]也可以定义为0(后面给出的求串的模式值的函数和串的模式匹配的函数,是next[0]=0的),这样,next[j]=k(0≤k<j)的意义都可以简单看成是:下标为j的字符的前面最多k个字符与开始的个字符相同。这样子问题就简单多了!
#include<cstdio> #include<cstring> using namespace std; const int MAX =200000+5; char a[MAX]; int next[MAX],n; void get_next() { int i=0,j=-1; next[0]=-1; while(i<n) { while(j>-1&&a[j]!=a[i]) { j=next[j]; } i++; j++; next[i]=j; printf("next[%d]=%d\n",i,next[i]); } } int main() { int T; scanf("%d",&T); while(T--) { int ans=0; scanf("%d %s",&n,a); get_next(); ans+=n+next[n]; for(int i=0;i<n;i++) { if(next[i]>0&&next[i]+1!=next[i+1]) { ans+=next[i]; } } printf("%d\n",ans%10007); } return 0; }