(一)题面:
样例输入
2
1
2
样例输出
1.0.0.0/8
2.0.0.0/8
样例输入
2
10/9
10.128/9
样例输出
10.0.0.0/8
样例输入
2
0/1
128/1
样例输出
0.0.0.0/0
(二)题意:
(中文题见题面)
(三)题解:
1、直接按照提示的步骤来写即可。
2、首先将非标准的ip标准化,这样便于处理,最后输出也是需要标准格式输出的。
3、标准化以后排序,到这里就可以拿60分了。
4、从小到大合并,这个步骤只需要判断后一个集合是否前一个集合的子集,然后合并一下即可,比较简单,做完有80分。
5、同级和并,这里类似于区间的合并,由于此时不存在完全包含的情况,故判断较为简单,具体的步骤按照提示来写即可,其中具体的原因仔细分析一下也不难得出。
6、具体的细节见代码。
(四)代码:
#include<iostream>
#include<iomanip>
#include<cstring>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<set>
#include<map>
#include<algorithm>
#define uint unsigned long long
using namespace std;
const int maxn=1e6+10;
string D_T_S(int d){ //数字->string
string s=d?"":"0";
while(d)s=s+(char)(d%10+'0'),d/=10;
reverse(s.begin(),s.end());return "/"+s;
}
struct IP{
string ip;uint a[5],val;
bool operator < (const IP &p)const{ //重载比较运算符
for(int i=0;i<5;i++)
if(a[i]!=p.a[i])return a[i]<p.a[i];
} //同级合并时得到a'
void init(uint b[5],uint _val,string _ip){
for(int i=0;i<5;i++)a[i]=b[i];val=_val;
a[4]--;ip=_ip.substr(0,_ip.find('/'))+D_T_S(a[4]);
}
void norm(){ //标准化
int l=ip.length(),pt=0,xt=0;
for(int i=0;i<l;i++)
if(ip[i]=='.')pt++;
else if(ip[i]=='/')xt++;
string ft=ip.substr(0,ip.find('/'));
string lt=xt?ip.substr(ip.find('/'),l):"";
for(int i=pt;i<3;i++)ft=ft+".0";
ft=ft+(xt?lt:D_T_S((pt+1)*8));ip=ft;
}
void info(){ //分离具体信息
int l=ip.length();
for(int i=0,t=0,s=0;i<l;i++,s=0){
while(i<l&&ip[i]!='.'&&ip[i]!='/')
s=s*10+ip[i++]-'0';
a[t++]=s;
}val=0;
for(int i=0;i<4;i++)val=val*256+a[i];
}
bool legal(){ //判断合法性
return a[4]<33&&val>>(32-a[4])<<(32-a[4])==val;
}
void interval(uint &l,uint &r){ //一个ip地址所匹配的所有地址区间
l=val>>(32-a[4])<<(32-a[4]);
r=val|((1ull<<(32-a[4]))-1);
}
}v[maxn];int sz;
bool sub_union(IP ip1,IP ip2,IP &res){ //判断两个同级的集合是否能合并
IP ap;ap.init(ip1.a,ip1.val,ip1.ip);
if(!ap.legal())return 0;
uint apl,apr,al,ar,bl,br;
ip1.interval(al,ar);
ip2.interval(bl,br);
ap.interval(apl,apr);
if(bl<=ar+1&&al==apl&&br==apr){res=ap;return 1;}
return 0;
}
void Union1(){ //第二步--从小到大合并
int p=0;
for(int i=1;i<sz;i++){
uint al,ar,bl,br;
v[p].interval(al,ar);
v[i].interval(bl,br);
if(!(al<=bl&&br<=ar))v[++p]=v[i];
}sz=p+1;
}
void Union2(){ //第三步--同级合并
int p=0;IP res;
for(int i=1;i<sz;i++){
if(sub_union(v[p],v[i],res)){
v[p]=res;
while(p>0&&sub_union(v[p-1],v[p],res))v[--p]=res;
}else v[++p]=v[i];
}sz=p+1;
}
int main(){ //主函数
cin.tie(0);
ios_base::sync_with_stdio(0);
int n;cin>>n;
for(int i=0;i<n;i++){
cin>>v[i].ip;
v[i].norm();v[i].info();
}sort(v,v+n);sz=n;Union1();Union2();
for(int i=0;i<sz;i++)cout<<v[i].ip<<'\n';
return 0;
}
(五)总结:
赛后AC,赛时0分,我真滴是服了,不知道当时写了什么QWQ。
其实那时候正好碰上期中考试,然后写代码写得比较少,这个题有是纯考验代码熟练度(个人认为),所以生疏了,平时还是要多加练习!!!
这次的第四题是真的简单,有点可惜...