ACM学习历程—Hihocoder 1289 403 Forbidden(字典树 || (离线 && 排序 && 染色))

http://hihocoder.com/problemset/problem/1289

这题是这次微软笔试的第二题,过的人比第三题少一点,这题一眼看过去就是字符串匹配问题,应该可以使用字典树解决。不过当时还有一个想法就是离线处理,把所有查询进行排序,然后用rule去匹配查询,进行染色处理,而且每个查询只进行一次染色。事实证明,如果比赛的时候采用第二种方法应该能拿全分,但是我用了第一种方法,导致只拿了10分。。。因为我没有考虑同一个rule出现两次的情况,但是字典树中会直接被后面的rule覆盖,所以需要判定更新最小的index,但是离线染色的情况只染一次,所以第二种会直接跳过这种坑点。。

字典树比较好考虑,就是直接存入rule的first mask部分,然后添加一个index和isok标记表示是第几个rule和rule的类型,然后后面的ip一旦匹配的话,只匹配index最小的。然后一些边界及不存在情况进行特判一下。

当时写完字典树WA只拿了10分,然后字典树也没有发现哪里写的有问题,就一直纠结与是不是数据溢出之类的。。唉,也只能说明水平还没到把,也不知道能不能进面试。

 

代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <set>
#include <map>
#include <queue>
#include <vector>
#include <string>
#define LL long long

using namespace std;

const int maxN = 100005;
const int maxLen = 32;//len表示数的二进制最大长度
struct Trie
{
    int index;
    int next[2];
}tree[maxN*maxLen];
bool isok[maxN*maxLen];
int cnt;

void initTree()
{
    cnt = 0;
    memset(tree, -1, sizeof(tree));
}

void add(int x, bool flag, int index, int len)
{
    int now = 0;
    bool k;
    for (int i = len-1; i >= 0; i--)
    {
        k = x&(1<<i);
        if (tree[now].next[k] == -1)
            tree[now].next[k] = ++cnt;
        now = tree[now].next[k];
    }
    if (tree[now].index == -1 || tree[now].index > index)//只因为这种情况,只拿了10分。。
    {
        tree[now].index = index;
        isok[now] = flag;
    }
}

bool query(int x)
{
    int v = -1, now = 0;
    bool k, flag;
    for (int i = maxLen-1; i >= 0; i--)
    {
        if (tree[now].index != -1)
        {
            if (v == -1 || v > tree[now].index)
            {
                v = tree[now].index;
                flag = isok[now];
            }
        }
        k = x&(1<<i);
        if (tree[now].next[k] == -1) break;
        now = tree[now].next[k];
    }
    if (tree[now].index != -1)
    {
        if (v == -1 || v > tree[now].index)
        {
            v = tree[now].index;
            flag = isok[now];
        }
    }
    if (v == -1) return true;
    else return flag;
}

int n, m;
char op[15];
char str[105];

void input()
{
    bool flag;
    int k, a, b, c, d, r, len;
    for (int i = 0; i < n; ++i)
    {
        scanf("%s%s", op, str);
        if (op[0] == 'a') flag = true;
        else flag = false;
        r = -1;
        len = strlen(str);
        for (int j = 0; j < len; ++j)
        {
            if (str[j] == '/')
            {
                sscanf(str+j+1, "%d", &r);
                str[j] = '\0';
            }
        }
        sscanf(str, "%d.%d.%d.%d", &a, &b, &c, &d);
        k = (a<<24)+(b<<16)+(c<<8)+d;
        if (r != -1) k >>= (32-r);
        else r = maxLen;
        add(k, flag, i, r);
    }
}

void work()
{
    bool flag;
    int k, a, b, c, d;
    for (int i = 0; i < m; ++i)
    {
        scanf("%d.%d.%d.%d", &a, &b, &c, &d);
        k = (a<<24)+(b<<16)+(c<<8)+d;
        flag = query(k);
        if (flag) printf("YES\n");
        else printf("NO\n");
    }
}

int main()
{
    //freopen("test.in", "r", stdin);
    while (scanf("%d%d", &n, &m) != EOF)
    {
        initTree();
        input();
        work();
    }
    return 0;
}
View Code

 

posted on 2016-04-09 14:03  AndyQsmart  阅读(649)  评论(3编辑  收藏  举报

导航