NOI2014 动物园

KMP补充:

  next【i】表示 1--i 的最长后缀等于前缀

  next【next【i】】 表示 1--i 的次长后缀等于前缀

题解:每个i 枚举所有next【i】 next【next【i】】。。。。。求小于长度 i/2 的个数

强行枚举next  50分


因为next【i】一定小于 i

所以建next【i】为 i 的爸爸 ,形成一个有根树,求每个节点的祖先有多少个小于i/2

我用栈加二分做        O(N *log N)

#include<cstring>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
int n;
//int num[1000001];
int next[2000001];
struct node
{
	int next;
	int to;
};
node bian[2000001];
int first[2000001];
int tt;
int stack[2000001];
char c[2000001];
int tail,size;
long long ans;

void inser(int a,int b)
{
	size++;
	bian[size].next=first[a];
	bian[size].to=b;
	first[a]=size;
}

void dfs(int x)
{
	int l,r,mid;
	if(x!=0)
	{
	l=0;
 	r=tail+1;
	while(r-l>1)
	  {
	  	mid=(r+l)>>1;
	  	if(stack[mid]<=(x>>1)) l=mid;
	  	else r=mid;
	  }
//	num[x]=r;
    ans=(ans*l)%1000000007;	
    }
	stack[++tail]=x;
	
	for(int i=first[x];i;i=bian[i].next)
	  {
	  	int u=bian[i].to;
	  	dfs(u);
	  }
    tail--;	  
}


int main()
{
	int _q=5*(10<<20);   
     char *_p=(char*)malloc(_q)+_q;
    __asm__("movl %0, %%esp\n"::"r"(_p));
	
	//freopen("zoo.in","r",stdin);
//	freopen("zoo.out","w",stdout);
	int i,j,k;
	scanf("%d\n",&tt);
	
	while(tt)
	{
		tt--;
//		memset(num,0,sizeof(num));
		memset(first,0,sizeof(first));
		size=0;
		next[0]=-1;
		gets(c+1);
		n=strlen(c+1);
		for(i=1;i<n;i++)
		  {
		  	 for(j=next[i];j!=-1;j=next[j])
		  	   if(c[i+1]==c[j+1]) break;
		  	 next[i+1]=j+1;   
		  }
		
		for(i=1;i<=n;i++)
		  inser(next[i],i);
		ans=1;  
		tail=0;
//	    tail=1;
//		stack[1]=0;
		dfs(0);
		cout<<ans;
		if(tt) cout<<endl;
	}
	
	
	
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值