-0-马上上计网了,感觉没什么空再看笛卡尔树了2333来水篇博客
还一个多礼拜就要去西安当分母了。第一次当分母内心还有点小紧张2333
然后我们来看看这个强行银牌题。。
队友还是强啊,五分钟把铜牌题公式甩我脸上了然鹅QWQ
这个银牌题其实也不是很难(如果看得懂题的话)
首先把所有ip换成二进制表示,题目表示如果有效前缀相同那么他们在一个子网内。
那么怎么才算有效前缀呢。看/后面那个数字,就是从高到低这个字数位是有效位
255.255.255.255/32为例
11111111.11111111.11111111.11111111有效前缀是32位就是全部有效
那么这个子网就只有一个ip就是255.255.255.255
如果是255.255.255.255/24那就只有24位了
所以画一画的话就会发现我们255.255.255.~这个~可以从0-255都是在这个子网内的
如果把上面/24换成23
可以发现111111111.11111111.1111111有效前缀是这些
那么之后的11111111.11111111.11111110.~和11111111.11111111.11111111.~
都在这个子网的支配下,那么我们很容易想到用字典树去匹配前缀。
那么我们的目的是至少还要多少才能支配剩下的子网且不能有冲突
现在我们在字典树上看,把ip表示为a.b.c.d/e
支配这个行为其实就是在字典树a.b.c.d这条链上找到高度为e的那个点
以这个点为根节点的所有网络都被这个子网支配
有链就说明以当前这个前缀为子网的话下面还有已存在的子网,会产生冲突
那么我们不产生冲突的话就要找到当前网络不存在的子网
也就是在字典树上找到还没有建的节点,那么就可以直接遍历整棵字典树
如果碰到没有建的节点,那么说明这个节点可以支配一个不会产生冲突的子网
这是我们需要的
如果碰到一个节点是有效前缀的末尾,那么这之后的所有子网都被这个前缀支配所以不需要添加子网
最后输出就行了2333
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 + 8;
struct Tire
{
int mark;
int next[2];
}t[N];
struct IP
{
int ip[40];
};
int tot = 0;
int x[40];
int root;
int NewNode()
{
tot ++;
t[tot].mark = 0;
for(int i = 0;i<2;i++)
t[tot].next[i] = 0;
return tot;
}
void init()
{
memset(t,0,sizeof(t));
tot = 0;
root = NewNode();
}
void ip2str(int a,int b,int c,int d,int e)
{
memset(x,0,sizeof(x));
for(int i = 7;i>=0;i--)
{
x[i] = a % 2;
a /= 2;
}
for(int i = 15;i >= 8;i--)
{
x[i] = b % 2;
b /= 2;
}
for(int i = 23;i >= 16;i--)
{
x[i] = c % 2;
c /= 2;
}
for(int i = 31;i >= 24;i--)
{
x[i] = d % 2;
d /= 2;
}
x[32] = e;
}
void insert()
{
int pos = x[32];
int r = root;
for(int i = 0;i<32;i++)
{
if(!pos)
{
t[r].mark = 1;
return;
}
//printf("%d %d %d\n",i, x[i],r);
if(!t[r].next[x[i]])
{
int temp = NewNode();
t[r].next[x[i]] = temp;
}
r = t[r].next[x[i]];
pos --;
}
}
vector<IP>ans;
int tar[40];
void dfs(int r,int d)
{
if(d > 32)
return;
if(!r)
{
IP temp;
for(int i = 0;i<33;i++)
temp.ip[i] = tar[i];
temp.ip[32] = d;
ans.push_back(temp);
return;
}
if(t[r].mark)
return;
tar[d] = 0;
dfs(t[r].next[0],d+1);
tar[d] = 1;
dfs(t[r].next[1],d+1);
tar[d] = 0;
}
void PrintIp(IP x)
{
int a,b,c,d,e;
a = b = c = d = e = 0;
for(int i = 0;i<8;i++)
{
a *= 2;
a += x.ip[i];
}
for(int i = 8;i<16;i++)
{
b *= 2;
b += x.ip[i];
}
for(int i = 16;i<24;i++)
{
c *= 2;
c += x.ip[i];
}
for(int i = 24;i<32;i++)
{
d *= 2;
d += x.ip[i];
}
e = x.ip[32];
printf("%d.%d.%d.%d/%d\n",a,b,c,d,e);
}
int main()
{
int T;
scanf("%d",&T);
int ka = 0;
while(T--)
{
int n;
scanf("%d",&n);
init();
for(int i = 0;i<n;i++)
{
int a,b,c,d,e;
scanf("%d.%d.%d.%d/%d",&a,&b,&c,&d,&e);
ip2str(a,b,c,d,e);
insert();
}
ans.clear();
memset(tar,0,sizeof(tar));
dfs(root,0);
printf("Case #%d:\n",++ka);
if(n == 0)
{
printf("1\n");
printf("0.0.0.0/0\n");
continue;
}
printf("%d\n",ans.size());
for(int i = 0; i != ans.size(); i ++)
PrintIp(ans[i]);
}
}