感谢 谢大,duoxida,zhsl ,教会了我几个训练赛当中没有想出来的题。
A Force Brute
题意: 没发现其水题本质啊.. 给定 N个单词, 然后问最大循环次数.
解法: KMP next数组的运用, 更详细的可以看这一篇总结 http://www.cnblogs.com/yefeng1627/archive/2013/04/28/3050027.html
这里就简要说下, 因为求next的过程是一个一个构造循环节的, (L+1)-next[L+1] 即为当前字符串的最小循环节长度, 而 L%( (L+1)-next[L+1] ) 表示目前 循环节构造了多少个,若为0则意味着构造满了一个循环. 而 L / ( (L+1) - next[L+1] ) 表是目前已经构造了的循环节数量. 所以最终结果为
令 d = (L+1) - next[L+1] , 则 ans = L/d + (L%d != 0)
若 next[L+1] = 1, 则代表整个串是 最小循环节. 其实发现可以不特殊处理的.
#include<cstdio> #include<cstring> #include<cstdlib> #include<map> #include<string> #include<algorithm> using namespace std; const int N = (int)1e5+10; char str[N*25], s[30]; int nxt[N], a[N], top, n; map<string,int> mp; int main(){ int T; scanf("%d", &T); getchar(); while( T-- ){ gets(str); top = n = 0; mp.clear(); char *p = strtok( str, " " ); while( p ){ if( mp.count(p) == 0 ) mp[p] = ++top; a[n++] = mp[p]; p = strtok( NULL, " " ); } // for(int i = 0; i < n; i++) // printf("%d ", a[i] ); puts(""); int i = 0, j = 1; nxt[1] = 0; while( j <= n ){ if( i == 0 || a[i-1] == a[j-1] ) nxt[++j] = ++i; else i = nxt[i]; } // for(int i = 1; i <= n+1; i++) // printf("%d ", nxt[i] ); puts(""); if( nxt[n+1] != 1 ){ int d = (n+1)-nxt[n+1]; printf("%d\n", n/d + (n%d!=0) ); } else puts("1"); } return 0; }