201812-3 CIDR合并
题解思路
计算包含IP前缀数目最少的等价前缀列表
第一步:排序
将所有IP前缀进行排序,以其IP地址为第一关键字,以前缀长度为第二关键字从小到大排序,形成一个列表。
第二步:从小到大合并
从头到尾扫描该列表,依次考虑其相邻的两个元素a,b:如果b的匹配集是a的匹配集的子集,则将b从列表中移除。如果b后仍有元素c,则此时a与c变为相邻的元素,应当继续考虑这对新的相邻元素,直到a的下一个元素不能被移除。然后继续依次处理列表中接下来的相邻元素。
可以证明,在此躺扫描结束之后,列表中不会存在任何两个元素a,b使得b的匹配集是a的匹配集的子集。
第三步:同级合并
从头到尾扫描该列表,依次考虑其相邻的两个元素a,b:如果a与b的前缀长度相同,则设a’为一个新的IP前缀,其IP地址与a相同,而前缀长度比a少1。如果a’合法且a的匹配集与b的匹配集的并集等于a’的匹配集,则将a与b从列表中移除,并将a’插入到列表中原来a,b的位置。与上一步不同的是,如果a’之前存在元素,则接下来应当从a’的前一个元素开始考虑;否则继续从a’开始考虑。
由于这道题对时间卡得紧,需要在同级合并那里使用链表优化,不然会超时
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=1e6+10;
long long P[34]; //保存2的幂次 P[i]=2^(33-i)
struct IP
{
ll s;
int len;
bool operator < (const IP &u) const
{
if(s<u.s) return true;
else if(s>u.s) return f