hihocoder #1289 : 403 Forbidden (2016 微软编程笔试第二题)

#1289 : 403 Forbidden

时间限制:10000ms
单点时限:1000ms
内存限制:256MB

描述

Little Hi runs a web server. Sometimes he has to deny access from a certain set of malicious IP addresses while his friends are still allow to access his server. To do this he writes N rules in the configuration file which look like:

allow 1.2.3.4/30
deny 1.1.1.1
allow 127.0.0.1
allow 123.234.12.23/3
deny 0.0.0.0/0

Each rule is in the form: allow | deny address or allow | deny address/mask.

When there comes a request, the rules are checked in sequence until the first match is found. If no rule is matched the request will be allowed. Rule and request are matched if the request address is the same as the rule address or they share the same first mask digits when both written as 32bit binary number.

For example IP "1.2.3.4" matches rule "allow 1.2.3.4" because the addresses are the same. And IP "128.127.8.125" matches rule "deny 128.127.4.100/20" because 10000000011111110000010001100100 (128.127.4.100 as binary number) shares the first 20 (mask) digits with 10000000011111110000100001111101 (128.127.8.125 as binary number).

Now comes M access requests. Given their IP addresses, your task is to find out which ones are allowed and which ones are denied.

输入

Line 1: two integers N and M.

Line 2-N+1: one rule on each line.

Line N+2-N+M+1: one IP address on each line.

All addresses are IPv4 addresses(0.0.0.0 - 255.255.255.255). 0 <= mask <= 32.

 

For 40% of the data: 1 <= N, M <= 1000.

For 100% of the data: 1 <= N, M <= 100000.

输出

For each request output "YES" or "NO" according to whether it is allowed.

样例输入
5 5
allow 1.2.3.4/30
deny 1.1.1.1
allow 127.0.0.1
allow 123.234.12.23/3
deny 0.0.0.0/0
1.2.3.4
1.2.3.5
1.1.1.1
100.100.100.100
219.142.53.100
样例输出
YES
YES
NO
YES
NO


题目大意:
给定N个允许接入或者拒绝的IP或者IP/掩码
再给M个IP地址,判断是否可以接入,可以输出YES,否则输出NO(没有匹配的输出YES)
1<=N,M<=100000
(判断的时候要按照N条规则的先后顺序判断的,遇到符合的就输出)
思路:
一开始没看到N和M的最大值,做法是,将N条规则中的IP转换为整数,在按照掩码位数得到掩码(没有掩码的按照掩码位数为32),
并将掩码和掩码位数存储到结构体数组中,对于测试的每一条IP,与结构体数组中的掩码,按照掩码位数进行比较,直到找到第一条
匹配的。 当然这种想法果断超时。

AC思路:
为了节省查询的时间,想到用map存储N条规则,但是map ,在查找是并不是按照N条规则给的顺序给你查找啊,所以在map<pnode,node>
pnode 是一个结构体,存储的是掩码和掩码的位数,node 存储的是顺序和是否允许接入;
当我们判断一个IP是否允许接入时,我们事先并不知道,掩码位数为多少的出现在前面,所以要从0~32位逐一枚举测试IP的掩码位数,查看是否在map
,查看是否在map中出现过,若出现了,比较出现的顺序,取出现较早的

#include <iostream>
#include <stdio.h>
#include <string>
#include <string.h>
#include <algorithm>
#include <vector>
#include <map>
#define maxn 110
#define inf 0x7fffffff
using namespace std;
struct node
{
    int pos;// 序号
    int flag;// 拒绝还是接受 1表示接受,0表示拒绝
    node()
    {

    }
    node(int x, int y)
    {
        pos = x;
        flag = y;
    }
    bool operator<(const node& b)
    {
        return pos < b.pos;
    }
};
struct pnode
{
    int k;// ip 值
    int num; // 子网掩码位数
    pnode()
    {

    }
    pnode(int x, int y)
    {
        k = x;
        num = y;
    }

    bool operator<(const pnode& b)const
    {
        if(k!=b.k) return k < b.k;
        else
        {
            return num < b.num;
        }
    }

};
map<pnode, node>my_map;
int Trans(int x,int y, int z, int w, int num)
{
    int ans = 0;
    if(num == 0)return ans;
    ans = ans|x;
    ans<<=8;
    ans = ans|y;
    ans<<=8;
    ans = ans|z;
    ans<<=8;
    ans = ans|w;
    int k = 32 - num;
    ans>>=k;
    ans<<=k;

    return ans;

}

int main()
{

    //freopen("data.txt","r",stdin);
    int n,m;
    char str[maxn];
    char c[20];
    int x,y,z,w;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        getchar();
        my_map.clear();
        for(int j = 0; j < n;j++)
        {
            gets(str);
            int len = strlen(str);
            bool f = false;
            for(int i = len - 1;i >= 0;i--)
            {
                if(str[i] == '/')
                {
                    f = true;
                    break;
                }
            }

            int num = 32;
            if(f)sscanf(str, "%s %d.%d.%d.%d/%d", c, &x,&y,&z,&w,&num);
            else sscanf(str, "%s %d.%d.%d.%d", c, &x,&y,&z,&w);

            int k = Trans(x,y,z,w,num);
            int flag = 0;
            pnode tmp_pnode;
            tmp_pnode.k = k;
            tmp_pnode.num = num;
            if(strcmp(c, "allow") == 0)
            {
                flag = 1;
            }

            if(my_map.find(tmp_pnode) == my_map.end())
            {
                my_map[tmp_pnode] = node(j,flag);
            }

        }

        while(m--)
        {
           scanf("%d.%d.%d.%d",&x,&y,&z,&w);
           int pos = inf;
           int flag = 1;
           for(int i = 0 ; i <= 32;i++)
           {
               int k = Trans(x,y,z,w,i);
               pnode tmp_pnode;
               tmp_pnode.k = k;
               tmp_pnode.num = i;

               if(my_map.find(tmp_pnode)!= my_map.end())
               {
                   node a = my_map[tmp_pnode];

                   if(pos > a.pos)
                   {
                       pos = a.pos;
                       flag = a.flag;
                   }
               }
           }

           if(flag == 1)puts("YES");
           else puts("NO");
        }
    }

}

  

转载于:https://www.cnblogs.com/acSzz/p/5378745.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值