2011 Asia Fuzhou Regional Contest-1005 hdu4125 Moles


题目描述:

    给N个数(标号为1-N)按顺序建一棵二叉排序树,然后按数字从小到大遍历这棵树,每走过一个标号为奇数的节点记录1,偶数记录0,访问完所有节点回到地面上之后便能得到一串0-1序列,之后给另外一个0-1串s,问遍历得到的串包含多少个s(可以重叠) n不大于600000


北大出的题还是很好的,题目读起来很简单,不是什么模板题不是超难的论文题也不是特简单的水题。解题思路很清晰,但却需要不断优化,否则10^5的数据很容易超时或者爆内存。这题改了N次,在TLE,MLE,RE折磨N次之后才勉强A掉


题目很简单,但有三个地方需要注意:

  1. 建树不能只是模拟插入过程递归写,N为10^5,给0、1、2、3.......N 时会超时,需要稳定Nlog(N)
  2. 遍历的时候不能递归写,会栈溢出
  3. 字符串匹配next数组需要处理到匹配串的长度,即需要算出next[m]

另外,建树遍历什么的一定不要用动态内存写,会很麻烦,最好提前开个数组


#include<iostream>
#include<cstdio>
#include<cstring>
#include<iterator>
#include<memory.h>
#include<set>

using namespace std;

bool visited[600005];
char str[1800005];
int cnt,ct,size,res,next[7007];

struct Node{
	int num;
	Node* left;
	Node* right;
};

struct cmp{
	bool operator()(const Node* a,const Node* b){
		return (a->num)<(b->num);
	}
};

Node* stac[1800005];
Node* node = new Node[600005];

set<Node*,cmp> visit;
set<Node*,cmp>::iterator it;


void Next(const char s[]){
	memset(next,0,sizeof(next));
	int j,t,m;
	t=next[0]=-1;
	j=0;
	m=strlen(s);
	while(j<m){
		if(t<0||s[j]==s[t]) next[++j]=++t;
		else t=next[t];
	}
	return;
}

void Mat(const char s1[],const char s2[]){
	int i,j,m;
	m=strlen(s2);
	i=j=0;
	while(i<ct){
	    if(j==m) res++;
        if(j<0||s1[i]==s2[j]){
            i++;
            j++;
        }
        else j=next[j];
    }
    if(j==m) res++;
}

void dfs(Node* curr){
	size=0;
	memset(visited,0,sizeof(visited));
	stac[size++]=curr;
	while(size>0){
		curr=stac[size-1];
		size--;
		if((curr->num)%2) str[ct++]='1';
		else str[ct++]='0';
		if(!visited[curr->num]){
			visited[curr->num]=true;
			if(curr->right){
				stac[size++]=curr;
				stac[size++]=curr->right;
			}
			if(curr->left){
				stac[size++]=curr;
				stac[size++]=curr->left;
			}
		}
	}
}

int main(){
	Node* tree;
	Node* tmpNode;
	int k,n,num;
	char harStr[7007];
	while(scanf("%d",&k)!=EOF){
		for(int p=1;p<=k;p++){
			visit.clear();
			ct=res=cnt=0;
			tree=NULL;
			scanf("%d",&n);
			scanf("%d",&num);
			node[cnt].num=num;
			node[cnt].left=NULL;
			node[cnt].right=NULL;
			tree=&node[cnt];
			cnt++;
			visit.insert(tree);
			for(int i=1;i<n;i++){
				scanf("%d",&num);
				node[cnt].num=num;
				node[cnt].left=NULL;
				node[cnt].right=NULL;
				tmpNode=&node[cnt];
				cnt++;
				it=visit.lower_bound(tmpNode);
				if(it!=visit.end()&&((*it)->left==NULL)){
					(*it)->left=tmpNode;
				}
				else{
					it--;
					(*it)->right=tmpNode;
				}
				visit.insert(tmpNode);
			}
			dfs(tree);
			scanf("%s",harStr);
			Next(harStr);
			Mat(str,harStr);
			printf("Case #%d: %d\n",p,res);
		}
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值