11年福州 E

/*
这题卡内存实在是太狗了……
思路很明确,就是几个算法杂糅在一起

刚开始粗糙的思路是建一个二叉搜索树,再按照中序遍历把树的点存一遍,最后跑一遍KMP
然而
    二叉搜索树用的set和数组revg,revg[i]存储对于值为i的节点下标
    中序遍历用dfs做
本题卡内存,正确的做法应该是
    二叉搜索树用的map,因为map是有序且按照第一维升序排列,故可以直接替换revg和set的作用
    中序遍历用手工栈做

失分点:
    1.卡内存:
        出现情况可能是递归爆栈、系统STL库存储空间需要过大、开的数组过多过大
学习的地方:
    1.map有序,可以用来二分查找
    2.卡内存时处理办法
    3.递归爆栈时可以改成手工栈操作

*/

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <cstdlib>
#include <string>
#include <vector>
#include <iterator>
#include <queue>
#include <utility>
#include <set>
#include <stack>
#include <map>
using namespace std;
#define mp make_pair
#define fi first
#define se second
const int MAXN = 600000 + 5;
int ne[MAXN][2];
int nodecnt;
int g[MAXN];//, revg[MAXN];//, vis[MAXN];
char out[MAXN * 3];
//int fa[MAXN];
int outcnt;
int fail[7000 + 5], n;
char mat[7000 + 5];
//set<int>S;
map<int,int>revg;
int sta[MAXN];
int num[MAXN];
void dfs(int mark)
{
    memset(num, 0, sizeof num);
    int head = 1, rear = 0;
    sta[++rear] = mark;
    while(head <= rear) {
        int u = sta[rear--];
//        printf("u = %d\n", u); system("pause");
        out[outcnt++] = (g[u] % 2) + '0';
        if(num[u] == 0) {
            num[u]++;
            if(ne[u][0] != -1) {
                sta[++rear] = u;
                sta[++rear] = ne[u][0];
                continue;
            }
        }
        if(num[u] == 1) {
            num[u]++;
            if(ne[u][1] != -1) {
                sta[++rear] = u;
                sta[++rear] = ne[u][1];
            }
        }
    }
}
//int const MAXT2 = MAXN * 2;
void failure()
{
    fail[0] = 0;
    int j = fail[0];
    int len = strlen(mat);
    for(int i=1; i<len; i++){
        while(j && mat[i]!=mat[j])
            j = fail[j];
        if(mat[i] == mat[j]) j++;
        fail[i + 1] = j;
    }
}
int match()
{
    int res = 0,now = 0,j=0;
    int n = strlen(mat);
    int m = outcnt;
    while(now + n - j <= m){
        if(j == n){
            res ++;
            j = fail[j];
        }
        while(j && mat[j]!=out[now])  j = fail[j];
        if(mat[j] == out[now]){
            j++;    now++;
        }
        else{
            now++;
        }
    }
    return res;
}
void init(int i){for(int u = 0 ; u < 2 ; u++) ne[i][u] = -1;}
int main()
{
    int T; scanf("%d", &T);
    for(int cas = 1 ; cas <= T ; cas++) {
        revg.clear();
//        S.clear();
        scanf("%d", &n);
        outcnt = 0;
        memset(ne, -1, sizeof ne);
        for(int i = 1 ; i <= n ; i++) scanf("%d", &g[i]);
        revg[0] = 0;
        init(1);
        init(0);
//        vis[0] = 0;
//        node[1].init();
        revg[g[1]] = 1;
        for(int i = 2 ; i <= n ; i++) {
//            if(i == 2) {
//                printf("node[1] = %d %d\n", node[1].ne[0], node[1].ne[1]);
//            }
            map<int,int>::iterator it = revg.lower_bound(g[i]);
            int t1, t2;
            if(it == revg.end()) {
                it--;
                t2 = 0;
                t1 = (*it).se;
            }
            else {
                t2 = (*it).se;
                if(it == revg.begin()) t1 = 0;
                else {
                    it--;
                    t1 = (*it).se;
                }
            }
//            t1 = revg[t1], t2 = revg[t2];
            int parent;
            if(t1 != 0 && ne[t1][1] == -1) parent = t1, ne[t1][1] = i;
            else parent = t2, ne[t2][0] = i;
//            printf("t1 = %d, ne[t1] = %d %d, t2 = %d, ne[t2] = %d %d\n", t1, ne[t1][0], ne[t1][1], t2, ne[t2][0], ne[t2][1]);
//            node[i].init();
            init(i);
            revg[g[i]] = i;
//            fa[i] = parent;
//            S.insert(g[i]);
        }
//        for(int i = 1; i <= n ; i++) {
//            printf("i = %d, u = %d, ne = %d %d\n", i, g[i], ne[i][0], ne[i][1]);
//        }
//        sort(g + 1, g + 1 + n);
        dfs(1);
        out[outcnt] = '\0';

//        printf("out = %s\n", out);
        scanf("%s", mat);
        failure();
        int res = match();
        printf("Case #%d: %d\n", cas, res);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值