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认证过程

类图 为了方便理解Spring Security认证流程,特意画了如下的类图,包含相关的核心认证类 概述 核心验证器 AuthenticationManager 该对象提供了认证方法的入口,接收一个Authentiaton对象作为参数; public interface AuthenticationManager {Authentication authenticate(Authenti

hdu2241(二分+合并数组)

题意:判断是否存在a+b+c = x,a,b,c分别属于集合A,B,C 如果用暴力会超时,所以这里用到了数组合并,将b,c数组合并成d,d数组存的是b,c数组元素的和,然后对d数组进行二分就可以了 代码如下(附注释): #include<iostream>#include<algorithm>#include<cstring>#include<stack>#include<que

day-51 合并零之间的节点

思路 直接遍历链表即可,遇到val=0跳过,val非零则加在一起,最后返回即可 解题过程 返回链表可以有头结点,方便插入,返回head.next Code /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode() {}*

CSP 2023 提高级第一轮 CSP-S 2023初试题 完善程序第二题解析 未完

一、题目阅读 (最大值之和)给定整数序列 a0,⋯,an−1,求该序列所有非空连续子序列的最大值之和。上述参数满足 1≤n≤105 和 1≤ai≤108。 一个序列的非空连续子序列可以用两个下标 ll 和 rr(其中0≤l≤r<n0≤l≤r<n)表示,对应的序列为 al,al+1,⋯,ar​。两个非空连续子序列不同,当且仅当下标不同。 例如,当原序列为 [1,2,1,2] 时,要计算子序列 [

【每日一题】LeetCode 2181.合并零之间的节点(链表、模拟)

【每日一题】LeetCode 2181.合并零之间的节点(链表、模拟) 题目描述 给定一个链表,链表中的每个节点代表一个整数。链表中的整数由 0 分隔开,表示不同的区间。链表的开始和结束节点的值都为 0。任务是将每两个相邻的 0 之间的所有节点合并成一个节点,新节点的值为原区间内所有节点值的和。合并后,需要移除所有的 0,并返回修改后的链表头节点。 思路分析 初始化:创建一个虚拟头节点

【Kubernetes】K8s 的安全框架和用户认证

K8s 的安全框架和用户认证 1.Kubernetes 的安全框架1.1 认证:Authentication1.2 鉴权:Authorization1.3 准入控制:Admission Control 2.Kubernetes 的用户认证2.1 Kubernetes 的用户认证方式2.2 配置 Kubernetes 集群使用密码认证 Kubernetes 作为一个分布式的虚拟

CSP-J基础之数学基础 初等数论 一篇搞懂(一)

文章目录 前言声明初等数论是什么初等数论历史1. **古代时期**2. **中世纪时期**3. **文艺复兴与近代**4. **现代时期** 整数的整除性约数什么样的整数除什么样的整数才能得到整数?条件:举例说明:一般化: 判断两个数能否被整除 因数与倍数质数与复合数使用开根号法判定质数哥德巴赫猜想最大公因数与辗转相除法计算最大公因数的常用方法:举几个例子:例子 1: 计算 12 和 18

【Python从入门到进阶】64、Pandas如何实现数据的Concat合并

接上篇《63.Pandas如何实现数据的Merge》 上一篇我们学习了Pandas如何实现数据的Merge,本篇我们来继续学习Pandas如何实现数据的Concat合并。 一、引言 在数据处理过程中,经常需要将多个数据集合并为一个统一的数据集,以便进行进一步的分析或建模。这种需求在多种场景下都非常常见,比如合并不同来源的数据集以获取更全面的信息、将时间序列数据按时间顺序拼接起来以观察长期趋势等

【Shiro】Shiro 的学习教程(二)之认证、授权源码分析

目录 1、背景2、相关类图3、解析3.1、加载、解析阶段3.2、认证阶段3.3、授权阶段 1、背景 继上节代码,通过 debug 进行 shiro 源码分析。 2、相关类图 debug 之前,先了解下一些类的结构图: ①:SecurityManager:安全管理器 DefaultSecurityManager: RememberMeManager:实现【记住我】功能

OpenStack离线Train版安装系列—3控制节点-Keystone认证服务组件

本系列文章包含从OpenStack离线源制作到完成OpenStack安装的全部过程。 在本系列教程中使用的OpenStack的安装版本为第20个版本Train(简称T版本),2020年5月13日,OpenStack社区发布了第21个版本Ussuri(简称U版本)。 OpenStack部署系列文章 OpenStack Victoria版 安装部署系列教程 OpenStack Ussuri版