hdu Moles(线段树&KMP)

来源:互联网 发布:赌博软件 编辑:程序博客网 时间:2024/05/06 19:47

Moles

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1936    Accepted Submission(s): 496


Problem Description
A mole is a strange mammal adapted to a subterranean lifestyle. It has invisible eyes and short, powerful limbs with large paws oriented for digging.

Before the catastrophic earthquake, a group of moles have perceived the disaster. They move to a safe place and want to dig holes under the ground. There are n moles, numbered from 1 to n. They stand in a line and dig holes one by one. The mole line is not necessary sorted by the mole number. Every mole should live in a hole dug by itself and every mole just digs one hole. The first mole in the line digs the first hole with a channel to the ground. Then other moles go down through that channel and dig more holes and channels. A hole may have at most three neighbors connected by channels, one is on the upper level, and the other two holes are on the lower level lying on the left side and the right side. When a mole reaches a hole, if its number is smaller than the hole owner's, it will go to the left-lower hole(or digs a left-lower hole and stays there when there is no left-lower hole), otherwise it will go to the right-lower hole(or digs a right-lower hole and stays there when there is no right-lower hole). Due to the excellent ability and well-designed layout, these holes and channels will not cross with each other.

Mouse Jerry is a friend of those moles. He comes to visit them and prepares gifts for every mole. There is a rule that the mole whose number is smaller must get the gift earlier than the mole whose number is larger. Jerry starts from the ground. He travels through the holes and channels to deliver his gifts. After giving out all his gifts, he comes back to the ground. In the mole world, it is interesting that the moles with odd numbers are males and others are females. When reaching a hole, Jerry takes a note about the gender of the hole owner(0 represents female and 1 represents male). When he gets back to the ground, he will get a 0-1 sequence. Now he wants to calculate the "harmony value". The harmony value represents the number of occurrences of a given "harmony string" in the above mentioned sequence. Occurrences may overlap.

Please note that Jerry is very smart so his travel distance is as small as possible.
 

Input
The first line contains an integer t meaning that there are t test cases(t <= 10).
For each test case :
The first line is an integer n meaning that there are n moles. (n <= 600000).
The second line contains n integers representing the mole line. Each integer is a mole's number and the first integer is the number of the first mole in the line.
The third line is the harmony string. The string length is not large than 7000.
 

Output
For each test case, please output the case number and the harmony value.
 

Sample Input
285 1 3 2 7 8 4 601101 2 3 4 5 6 7 8 9 101010
 

Sample Output
Case #1: 4Case #2: 8(Please note that there is a blank before '#' and after ':')
Hint
In the first test case, the 0-1 sequence of the first case is "111010111101011", and the number of occurrences of harmony string "01" is 4.
 

Source
2011 Asia Fuzhou Regional Contest
 

Recommend
lcy   |   We have carefully selected several similar problems for you:  4126 4121 4124 4127 4128 
题意:
给1~n组成的n个数,按输入顺序插入到平衡二叉树中,现在按1~n从小到大的顺序从根开始访问节点,每遇到一个节点i,如果i为奇数则序列+‘1’,如果i为偶数则序列+‘0’,这样得到一个序列txt,给一个01序列s,求s在txt中出现的次数,可以重叠。
思路:
比赛时直接模拟建树超时了。下来看了下别人的题解才知道这题不能模拟建树。因为如果这个数退化成一条链的话建树的时间复杂度就为O(n^2)。6*10^5的数据肯定会超时。
但是要得到那个01序列必须得建树。所以就要想更高效的算法了。一般高效的东西都会牵涉到性质。这题就利用到了搜索平衡二叉树的性质。
对于新插入的节点,其父亲要么是比自己大的最小的那个,或比自己小的最大的那个。为什么呢?
其实很简单。如果队平衡二叉树中序遍历的话。那么得到的一定是一个升序序列。所以新插入的节点,其父亲要么是比自己大的最小的那个,或比自己小的最大的那个。这样才能保证遍历后满足升序。
问题就转化成了,给一个数,求出在它之前的数序列中小于它的最大值或大于它的最小值。而这个问题可以用线段树维护,每个区间维护该区间已经放了数的最大值和最小值,如果查小于val的最大值,如果va>mid,则直接返回max(左区间的最大值,查右边)。因为左边的数都比val小直接取max就够了。而右边则只能取一部分所以要继续往下查找。
同理查询大于va的最小值。这样时间复杂度就优化到O(n*log(n))了。
树建好后就差dfs得到序列了。如果直接dfs肯定Runtime Error(STACK_OVERFLOW).
有时候题目当中的数据范围是N<=100000甚至更大,如果树是一条链的情况,程序用递归来实现一定会导致栈溢出。
大部分评测机的栈空间限制只有2MB,稍微差一点的可能会是1MB甚至更小。因此,我们可以考虑把那些剩余的内存分配给栈空间,从而解决这种栈溢出的问题。
对于C++语言,我们可以在程序前面加上这样一句命令:
#pragma comment(linker, "/STACK:1024000000,1024000000")

#pragma comment( comment-type ,["commentstring"] )
comment-type是一个预定义的标识符,指定注释的类型,应该是compiler,exestr,lib,linker之一。
commentstring是一个提供为comment-type提供附加信息的字符串。
其实,这个命令目的就是人工分配内存为栈内存。可以把内存当中空余的内存分配给栈,使一般正常操作的时候不会出现栈溢出的情况。
剩下的工作就是水KMP了。
详细见代码:
#include <iostream>#include<stdio.h>#include<string.h>#pragma comment(linker,"/STACK:1024000000,1024000000")//手动开栈using namespace std;const int maxn=600010;const int INF=0x3f3f3f3f;int ma[maxn<<2],mi[maxn<<2];//维护最大最小值int ch[maxn][2],f[7005];int ptr,id,ans;char txt[maxn<<2],mos[7005];void getf(char *p,int len){    int i,j,n=len;    f[0]=f[1]=0;    for(i=1;i<n;i++)    {        j=f[i];        while(j&&p[j]!=p[i])            j=f[j];        f[i+1]=p[j]==p[i]?j+1:0;    }}void kmp(char *T,char *p){    int i,j,n=ptr,m=strlen(p);    getf(p,m);    for(i=0,j=0;i<n;i++)    {        while(j&&T[i]!=p[j])            j=f[j];        if(p[j]==T[i])            j++;        if(j==m)        {            ans++;            j=f[j];        }    }}void btree(int L,int R,int k){    int mid,ls,rs;    ma[k]=0;    mi[k]=INF;    if(L==R)    {        ch[L][0]=ch[L][1]=0;//记录左右儿子        return ;    }    ls=k<<1;    rs=ls|1;    mid=(L+R)>>1;    btree(L,mid,ls);    btree(mid+1,R,rs);}void update(int L,int R,int k,int p)//单点更新{    int mid,ls,rs;    if(L==R)    {        ma[k]=mi[k]=p;        return ;    }    ls=k<<1;    rs=ls|1;    mid=(L+R)>>1;    if(p<=mid)        update(L,mid,ls,p);    else        update(mid+1,R,rs,p);    ma[k]=max(ma[ls],ma[rs]);    mi[k]=min(mi[ls],mi[rs]);}int qumax(int L,int R,int k,int val)//找到比val小的最大的结点{    int mid,ls,rs;    if(L==R)        return ma[k];    ls=k<<1;    rs=ls|1;    mid=(L+R)>>1;    if(val<=mid)        return qumax(L,mid,ls,val);    else        return max(ma[ls],qumax(mid+1,R,rs,val));}int qumin(int L,int R,int k,int val)//找到比val大最小的结点{    int mid,ls,rs;    if(L==R)        return mi[k];    ls=k<<1;    rs=ls|1;    mid=(L+R)>>1;    if(val>mid)        return qumin(mid+1,R,rs,val);    else        return min(qumin(L,mid,ls,val),mi[rs]);}void gettxt(int root){    //printf("r %d\n",root);    char op=(root&1)+'0';    txt[ptr++]=op;    if(ch[root][0])    {        gettxt(ch[root][0]);        txt[ptr++]=op;    }    if(ch[root][1])    {        gettxt(ch[root][1]);        txt[ptr++]=op;    }}int getint()//优化输入{    int an=0;    char ch=getchar();    while(ch<'0'||ch>'9')        ch=getchar();    do    {        an=an*10+ch-'0';        ch=getchar();    }while(ch>='0'&&ch<='9');    return an;}int main(){    int t,n,i,root,al,ar,cas=1;    scanf("%d",&t);    while(t--)    {        ptr=ans=0;        scanf("%d",&n);        btree(1,n,1);        root=id=getint();        update(1,n,1,id);        for(i=1;i<n;i++)        {            id=getint();            al=qumax(1,n,1,id);            ar=qumin(1,n,1,id);            //printf("id %d al %d ar %d\n",id,al,ar);            if(al==0)//没有比id小的值                ch[ar][0]=id;            else if(ar==INF)//没有比id大的值                ch[al][1]=id;            else            {                if(ch[ar][0])                    ch[al][1]=id;                else                    ch[ar][0]=id;            }            update(1,n,1,id);        }        gettxt(root);        txt[ptr]=0;        //printf("%s\n",txt);        scanf("%s",mos);        kmp(txt,mos);        printf("Case #%d: %d\n",cas++,ans);    }    return 0;}