程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> HDU 4125 2011福州現場賽E題 KMP+笛卡爾樹

HDU 4125 2011福州現場賽E題 KMP+笛卡爾樹

編輯:C++入門知識

題意就不描述了。 主要說一下我的構造第一個串的過程
 
對給出的序列,比如5 1 3 2 7 8 4 6
 
給每個數按輸入的順序對應一個編號
 
5  1  3  2  7  8  4  6
 
1  2  3  4  5  6  7  8
 
然後我們手動建這顆二叉搜索樹。觀察它,可以發現,每個結點的編號是滿足堆的性質。
 
也就是如果把這個編號當做每個結點的第二個關鍵字,這就是一個笛卡爾樹了
 
而建立笛卡爾樹的方法,如果以前做過POJ 2201的話,應該明白
 
首先按照第一個關鍵字排序
 
變為
 
第一關鍵字:1  2  3  4  5  6  7  8
 
第二關鍵字:2  4  3  7  1  8  5  6
 
然後我們找到那個第二關鍵字最小的結點,上面的例子的話就是第一關鍵字為5的結點
 
那麼我們首先經過的就是5.
 
然後看5的左孩子區間[1,4],同理找最小,就是第一關鍵字為1的結點,此時要經過的就是1.然後發現1沒有左孩子
 
就進入右孩子[2,4]去找,找到第一關鍵字為3的點,那麼經過的就是3了,再找左孩子,經過了2,此時要退回去,又經過了3,然後找3的右孩子
 
經過了4,再退回去,又經過了3,再往回退,然後經過3的父親就是1,再退回去就經過了5,同理處理5的右孩子區間
 
就這樣,記錄經過的結點,串就構造出來了,然後KMP就行了
 
加完輸入優化後,這種方法用線段樹實現後的速度是1900ms+
 
當然,必須自己手寫堆棧  很蛋疼
 
當然此題可以用RMQ,但對於此題來講,RMQ有點卡空間 畢竟60W*log(60W) 不小,不過我寫了一遍後發現,竟然卡著空間過了,不過竟然比線段樹還慢,而且是我預處理log的情況下,真是神奇了。
 
下面代碼中的solve函數是我剛開始寫的遞歸,只不過爆棧了,改成手寫堆棧後,起到的作用也就是看起來容易明白
 
 
 
 
 
[cpp]
#include <iostream>  
#include <cstdio>  
#include <cmath>  
#include <string>  
#include <cstring>  
#include <cstdlib>  
#include <algorithm>  
#define lch(x) x<<1  
#define rch(x) x<<1|1  
#define lson l,m,rt<<1  
#define rson m+1,r,rt<<1|1  
using namespace std; 
 
const int inf = 111111111; 
const int maxn = 1009; 
const double esp = 1e-6; 
const int N = 600009; 
 
int n; 
int st[N]; 
int now[N]; 
struct point 

    int a, b; 
    int id; 
} pp[N]; 
struct node 

    int x, id; 
} p[N]; 
int hash[N]; 
 
bool cmp(node x, node y) 

    return x.x < y.x; 

 
int mi[4*N]; 
void build(int l, int r, int rt) 

    if(l == r) 
    { 
        mi[rt] = p[l].id; 
        return ; 
    } 
    int m = (l + r) >> 1; 
    build(lson); 
    build(rson); 
    mi[rt] = min(mi[lch(rt)], mi[rch(rt)]); 

int query(int L, int R, int l, int r, int rt) 

    if(L <= l && R >= r) return mi[rt]; 
    int ret = inf; 
    int m = (l + r) >> 1; 
    if(L <= m) ret = min(ret, query(L, R, lson)); 
    if(R > m) ret = min(ret, query(L, R, rson)); 
    return ret; 

int len; 
char s1[1888888], s2[7777]; 
 
int solve(int s, int t) 

    if(s > t) return 0; 
    int id = query(s, t, 1, n, 1); 
    int k = hash[id] % 2; 
    s1[len++] = k + '0'; 
    if(solve(s, hash[id] - 1)) 
    { 
        s1[len++] =k + '0'; 
    } 
    if(solve(hash[id]  + 1, t)) 
    { 
        s1[len++] =k + '0'; 
    } 
    return 1; 

int next[11111]; 
void get_next(char *str) 

    int i = 0, j = -1, l = strlen (str); 
    next[0] = j; 
    while(i < l) 
    { 
        if(j == -1 || str[j] == str[i]) 
        { 
            i++, j++; 
            next[i]= j; 
        } 
        else j = next[j]; 
    } 

int KMP(char *str1, char *str2) 

    int ans = 0; 
    int i = -1, j = -1, l1 = strlen(str1), l2 = strlen(str2); 
    while(i < l1) 
    { 
        if(j == -1 || str1[i] == str2[j]) 
        { 
            i++, j++; 
        } 
        else j = next[j]; 
        if(j == l2) 
            ans++; 
    } 
    return ans; 

int in() 

    char ch; 
    int a = 0; 
    while((ch = getchar()) == ' ' || ch == '\n'); 
    a += ch - '0'; 
    while((ch = getchar()) != ' ' && ch != '\n') 
    { 
        a *= 10; 
        a += ch - '0'; 
    } 
    return a; 

int main() 

    int ca, tt=0; 
    scanf("%d", &ca); 
    while(ca--) 
    { 
        scanf("%d", &n); 
        for(int i = 1; i <= n; i++) p[i].x = in(), p[i].id = i; 
        sort(p + 1 ,p + n + 1, cmp); 
        for(int i = 1; i <= n; i++) hash[p[i].id] = i; 
        build(1, n, 1); 
        len = 0; 
        //solve(1, n);  
        memset(now, 0, sizeof(now)); 
        pp[0].a = 1; 
        pp[0].b = n; 
        pp[0].id = 1; 
        st[0] = 0; 
        int top = 0; //模擬棧st的坐標  
        len = 0; //串長  
        int cnt = 0; //棧裡存的結構體point的坐標  
        while(top>=0) 
        { 
            int num = st[top]; 
            int a = pp[num].a; 
            int b = pp[num].b; 
            int id = pp[num].id; 
            char k = hash[id] % 2+'0'; 
            //s1[len++] = k;  
 
 
            if(now[num]==0) //第一次  
            { 
                if(hash[id]>a) //有左孩子  
                { 
                    pp[++cnt].a = a; 
                    pp[cnt].b = hash[id]-1; 
                    pp[cnt].id = query(a, hash[id]-1, 1, n, 1); 
                    st[++top] = cnt; 
                    s1[len++] = k; 
                } 
                now[num] = 1; 
            } 
            else if(now[num]==1) //第二次,處理完左孩子了  
            { 
                if(hash[id]<b) //有右孩子  
                { 
                    pp[++cnt].a = hash[id]+1; 
                    pp[cnt].b = b; 
                    pp[cnt].id = query(hash[id]+1, b, 1, n, 1); 
                    st[++top] = cnt; 
                    s1[len++] = k; 
                } 
                now[num] = 2; 
            } 
            else if(now[num]==2) //第三次,兩個孩子都處理完了  
            { 
                s1[len++] = k; 
                --top; 
            } 
        } 
 
        s1[len] = '\0'; 
        // cout<<s1<<endl;  
        scanf("%s", s2); 
        get_next(s2); 
        printf("Case #%d: %d\n", ++tt, KMP(s1, s2)); 
    } 
    return 0; 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved