luogu P2375 [NOI2014]动物园

luogu P2375 [NOI2014]动物园

大意

就是定义一个类似 K M P KMP KMP中的 n x t nxt nxt 数组的东西 n u m num num,不过 n u m i num_i numi表示前缀 s t [ 1... i ] st[1...i] st[1...i] 能匹配的前缀的数量且匹配的前缀的长度不能超过 i / 2 i/2 i/2
学过AC自动机的都知道这很简单,如果不考虑长度限制,个数就直接在构造 n x t nxt nxt数组的时候继承一下 n u m num num就行了
n u m [ i ] = n u m [ n x t [ i ] ] + 1 num[i] = num[nxt[i]] + 1 num[i]=num[nxt[i]]+1
就这样,如果匹配的时候长度不合法就往前跳,然后直接跑一遍就完事了
code:

// luogu-judger-enable-o2
#include<bits/stdc++.h>
#define N 2000005
using namespace std;
int t, n, nxt[N], ha[N];
char st[N];
int main(){
	scanf("%d", &t);
	while(t --){
		memset(nxt, 0, sizeof nxt);
		memset(ha, 0, sizeof ha);
		scanf("%s", st + 1);
		int n = strlen(st + 1);
		int j = 0;ha[1] = 1;
		for(int i = 1; i < n; i ++){
			while(j && st[j + 1] != st[i + 1]) j = nxt[j];
			if(st[j + 1] == st[i + 1]) j ++;
			nxt[i + 1] = j, ha[i + 1] = ha[j] + 1;//构造nxt和num(ha)
		}
		j = 0;
		long long ans = 1;
		for(int i = 0; i <= n; i ++){
			while(j && st[j + 1] != st[i + 1]) j = nxt[j];//正常的跳
			if(st[j + 1] == st[i + 1]) j ++;//匹配一波
			while(j * 2 > i + 1) j = nxt[j];//如果长度不合法就继续往前跳,注意这里是求i+1位的
			ans = ans * (ha[j] + 1) % 1000000007;//记得mo一蛤
		}
		printf("%lld\n", ans);
	}
	return 0;
}

总结

NOI竟然考这种水题
这应该算是签到题吧,只要冷静分析还是做得出来的

posted @ 2019-08-10 20:24  lahlah  阅读(19)  评论(0编辑  收藏  举报