Bzoj3670: [Noi2014]动物园

题面

传送门

Sol

这是一道阅读理解题,读了好久才明白意思。。。
首先可以想到处理出next数组,每次的位置i跳next跳到长度小于i的一半位置,然后继续跳到零统计此时跳的次数就是答案
那么暴力就是(O(n^2))
让我们一起膜拜yyb大佬的倍增跳next

那么优化就是在求next的时候再开一个指针,每次强制跳到i的一半的位置。。。
再开数组cnt,每次由next指针的位置的cnt+1转移而来,然后就没了

# include <bits/stdc++.h>
# define RG register
# define IL inline
# define Fill(a, b) memset(a, b, sizeof(a))
using namespace std;
typedef long long ll;
const int _(1e6 + 1), Zsy(1e9 + 7);

IL ll Read(){
    RG ll x = 0, z = 1; RG char c = getchar();
    for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1;
    for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48);
    return x * z;
}

int l, ans, nxt[_], cnt[_];
char s[_];

int main(RG int argc, RG char* argv[]){
	for(RG int T = Read(); T; --T){
		scanf(" %s", s + 1); cnt[1] = ans = 1; l = strlen(s + 1);
		for(RG int i = 2; i <= l; ++i) nxt[i] = cnt[i] = 0;
		for(RG int i = 2, j = 0, k = 0; i <= l; ++i){
			while(j && s[i] != s[j + 1]) j = nxt[j];
			if(s[i] == s[j + 1]) nxt[i] = ++j;
			cnt[i] = cnt[j] + 1;
			while(k && s[i] != s[k + 1]) k = nxt[k];
			if(s[i] == s[k + 1]) ++k;
			while((k << 1) > i) k = nxt[k];
			ans = 1LL * ans * (cnt[k] + 1) % Zsy;
		}
		printf("%d
", ans);
	}
	return 0;
}

原文地址:https://www.cnblogs.com/cjoieryl/p/8309922.html