201812 CSP认证 | CIDR合并

2024-03-27 04:04
文章标签 csp 认证 合并 201812 cidr

本文主要是介绍201812 CSP认证 | CIDR合并,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

CIDR合并
难是真的不难但是也写了我几个小时服了
这道题在有计网的基础上就很好理解了,没有在格式上有任何刁难你的。这里不讲背景了
官网提交结果以及满分代码如下:
在这里插入图片描述

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<string, int> PSI;
const int N = 1e5 + 10;
int n;
struct node{string ip;int len;ll ten;  //ip前缀的十进制表示:为了方便排序
};
vector<node> ipPool;
vector<node> merge1; //第一轮合并的结果
vector<node> res;   //同级合并的最终结果
int to_int(string str)
{stringstream ssin(str);int x;ssin >> x;return x;
}
string to_str(int m)
{stringstream ssin;ssin << m;string str;ssin >> str;return str;
}
//用于第一步排序
bool cmp(node x, node y)
{if(x.ten == y.ten) return x.len < y.len;else return x.ten < y.ten;
}
//处理一个输入的ip,将其处理后存储到ipPool中
void handle(string str)
{int k = str.find('/');int len = 0; node temp;if(k != -1)  { len = to_int(str.substr(k + 1)); str = str.substr(0, k); }//开始解析ip, 将字符串按照'.'分割开来vector<string> vec;for(int i = 0, j = 0; i < str.size(); i = j + 1){  //将str用'+'分割开来j = str.find('.', i);  //从下标i开始找+号if(j == -1) j = str.size();vec.push_back(str.substr(i, j - i));}if(!len) len = vec.size() * 8;  //省略了长度型的ip书写方式if(vec.size() != 4){int sz = vec.size();for(int i = 1;i <= 4 - sz;i ++){vec.push_back("0");  //补0}}string ip = ""; ll ten = 0;  //将ip转化为十进制的数字for(int i = 0;i < vec.size();i ++) {ip = ip + vec[i] + '.';ll x = to_int(vec[i]);x <<= ((3 - i) * 8);ten += x;}ip = ip.substr(0, ip.size() - 1); //删去最后一个点ip += "/" + to_str(len);temp.ip = ip; temp.len = len; temp.ten = ten;ipPool.push_back(temp);
}//判断ipPool中b位置ip的匹配集是否是a位置ip匹配集的子集
bool subset(int a, int b)
{int lena = ipPool[a].len, lenb = ipPool[b].len;if(lena > lenb) return false;//接下来是lena <= lenb的情况,也就是二者的前lena个bit位置必须相同int delta = 32 - lena;int tena = ipPool[a].ten >> delta, tenb = ipPool[b].ten >> delta;  //只保留前lena位int temp = tena ^ tenb;if(temp) return false;  //前lena个bit位不相同return true;
}
//将ipPool中的元素从小到大进行合并
void small_Large_Merge()
{int a = 0, b = 1;bool st[N]; //考虑某个位置的元素是否存在memset(st, true, sizeof st);while(b < n){    //n也是ipPool的大小if(subset(a, b)){ st[b] = false; b ++; }else{ a = b; b ++; }}for(int i = 0;i < n;i ++){if(st[i]) merge1.push_back(ipPool[i]);}
}
//对merge1进行同级合并
void final_Merge()
{int a = 0, b = 1, sz = merge1.size();bool st[N];memset(st, true, sizeof st);  //功能同前面相同while(b < sz){node t;  //存储中间结果int lena = merge1[a].len, lenb = merge1[b].len;bool flag = false;  //是否能合并if(lena == lenb){//看二者是否能合并, 也就是看前len - 1位置是否完全相同,且最后一位不同int delta = 32 - lena;int tena = merge1[a].ten >> delta, tenb = merge1[b].ten >> delta;int tena2 = merge1[a].ten >> (delta + 1), tenb2 = merge1[b].ten >> (delta + 1);int cnt = 0;   //用来记录前len位有几位不相同int temp = tena ^ tenb;while(temp){cnt ++;temp &= (temp - 1);}temp = tena2 ^ tenb2;if(!temp && cnt == 1){  //前len - 1相同,第len不同,可以合并flag = true;t.ten = merge1[a].ten;t.len = merge1[a].len - 1; //长度不同string ip = merge1[a].ip;int k = ip.find('/');ip = ip.substr(0, k + 1);ip += to_str(t.len);t.ip = ip;}}if(flag){merge1[a] = t; st[b] = false;  //更新; a向前回溯if(a > 0){   //a > 0才有回溯的必要,注意这里st[0]是不可能为false的b = a; a --;while(!st[a]) a --;}else { //无需向前找了while(b < sz && !st[b]) b ++;};}else {a = b;b ++;while(b < sz && !st[b]) b ++;}}for(int i = 0;i < sz;i ++){if(st[i]) res.push_back(merge1[i]);}
}int main()
{ios::sync_with_stdio(false); cin.tie(0);cout.tie(0);cin >> n;for(int i = 0;i < n;i ++){string ip; cin >> ip;handle(ip);}sort(ipPool.begin(),ipPool.end(), cmp);//现在开始从小到大合并small_Large_Merge();//同级合并final_Merge();for(auto x : res){cout << x.ip << endl;}return 0;
}

本题我用了位运算来实现。能否合并的关键就是看前几位是否是相同的,如果前x位相同,第x + 1的异或结果为1的话,此时两个就可以合并成一个。因此我设置了一个len来保存ip地址的十进制数。
但就是这个我改了很久的错误
第62行我的初始代码是:ten += ( x << ((3 - i) * 8) ),结果总是负数
后来又测试了几个如下:
在这里插入图片描述
其实就是符号的问题。
如果我直接对128移位置,只在低位补零;此时的x的表示形式就是10000000 0000000 0000000 0000000。从补码的角度来说,因为最高位为1,此时就是负数!!!
而我若先赋值为128,此时这个数据只是存在与x空间的存储形式为00000000 00000000 00000000 10000000,再移位;此时变为00000000 10000000 0000000 0000000 0000000最高位仍然为0

这篇关于201812 CSP认证 | CIDR合并的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/850877

相关文章

Spring Security自定义身份认证的实现方法

《SpringSecurity自定义身份认证的实现方法》:本文主要介绍SpringSecurity自定义身份认证的实现方法,下面对SpringSecurity的这三种自定义身份认证进行详细讲解,... 目录1.内存身份认证(1)创建配置类(2)验证内存身份认证2.JDBC身份认证(1)数据准备 (2)配置依

SpringSecurity JWT基于令牌的无状态认证实现

《SpringSecurityJWT基于令牌的无状态认证实现》SpringSecurity中实现基于JWT的无状态认证是一种常见的做法,本文就来介绍一下SpringSecurityJWT基于令牌的无... 目录引言一、JWT基本原理与结构二、Spring Security JWT依赖配置三、JWT令牌生成与

SpringSecurity6.0 如何通过JWTtoken进行认证授权

《SpringSecurity6.0如何通过JWTtoken进行认证授权》:本文主要介绍SpringSecurity6.0通过JWTtoken进行认证授权的过程,本文给大家介绍的非常详细,感兴趣... 目录项目依赖认证UserDetailService生成JWT token权限控制小结之前写过一个文章,从S

springboot security使用jwt认证方式

《springbootsecurity使用jwt认证方式》:本文主要介绍springbootsecurity使用jwt认证方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地... 目录前言代码示例依赖定义mapper定义用户信息的实体beansecurity相关的类提供登录接口测试提供一

Python实现合并与拆分多个PDF文档中的指定页

《Python实现合并与拆分多个PDF文档中的指定页》这篇文章主要为大家详细介绍了如何使用Python实现将多个PDF文档中的指定页合并生成新的PDF以及拆分PDF,感兴趣的小伙伴可以参考一下... 安装所需要的库pip install PyPDF2 -i https://pypi.tuna.tsingh

SpringSecurity 认证、注销、权限控制功能(注销、记住密码、自定义登入页)

《SpringSecurity认证、注销、权限控制功能(注销、记住密码、自定义登入页)》SpringSecurity是一个强大的Java框架,用于保护应用程序的安全性,它提供了一套全面的安全解决方案... 目录简介认识Spring Security“认证”(Authentication)“授权” (Auth

一文详解kafka开启kerberos认证的完整步骤

《一文详解kafka开启kerberos认证的完整步骤》这篇文章主要为大家详细介绍了kafka开启kerberos认证的完整步骤,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录一、kerberos安装部署二、准备机器三、Kerberos Server 安装1、配置krb5.con

使用Apache POI在Java中实现Excel单元格的合并

《使用ApachePOI在Java中实现Excel单元格的合并》在日常工作中,Excel是一个不可或缺的工具,尤其是在处理大量数据时,本文将介绍如何使用ApachePOI库在Java中实现Excel... 目录工具类介绍工具类代码调用示例依赖配置总结在日常工作中,Excel 是一个不可或缺的工http://

使用Python创建一个能够筛选文件的PDF合并工具

《使用Python创建一个能够筛选文件的PDF合并工具》这篇文章主要为大家详细介绍了如何使用Python创建一个能够筛选文件的PDF合并工具,文中的示例代码讲解详细,感兴趣的小伙伴可以了解下... 目录背景主要功能全部代码代码解析1. 初始化 wx.Frame 窗口2. 创建工具栏3. 创建布局和界面控件4

Python自动化办公之合并多个Excel

《Python自动化办公之合并多个Excel》在日常的办公自动化工作中,尤其是处理大量数据时,合并多个Excel表格是一个常见且繁琐的任务,下面小编就来为大家介绍一下如何使用Python轻松实现合... 目录为什么选择 python 自动化目标使用 Python 合并多个 Excel 文件安装所需库示例代码