题意:
判断是否存在一棵树,满足它有 aaa 个一度点和 bbb 个三度点,如果存在请给出一个节点数不超过 200020002000 的构造,否则输出 000 。
首先我们来分点考虑:
-
对于 Subtask2:b=0Subtask2:b=0Subtask2:b=0 的情况
- 考虑如下情况:
1. 对于 a=0a=0a=0 的情况,直接输出 111 即可(即只有一个节点)。
2. 对于 a=1a=1a=1 和 a=3a=3a=3 的情况,我们无法构造,输出 000 。
3. 对于不同于以上三种的情况,考虑菊花图。即 111 号节点向外发散 aaa 个点,可以构造出满足题意的树
- 考虑如下情况:
-
对于 Subtask3:b=a−2Subtask 3 : b=a-2Subtask3:b=a−2 的情况
- 可以构造出这样一棵树:
- 对于奇数号的节点,它们都有左右儿子,而偶数号节点它们左右儿子都没有。即形如 111 号节点的左儿子为 222 号节点,右儿子为 333 号节点, 111 号节点的右儿子 333 号节点又有左儿子为 444 号节点,右儿子为 555 号节点,以此类推……
- 通过这样的方式,我们发现其实只有 111 号节点是附加的,是一个二度点,其他的点要么是一度点,要么是三度点。这样构造下来刚好有 aaa 个一度点和 bbb 个三度点。那么对于 0≤a,b≤2000 \leq a,b \leq 2000≤a,b≤200 的数据,这棵树的节点不会超过 401401401 个点,符合题意。
- 可以构造出这样一棵树:
-
现在来考虑对于全部的数据:
我们可以从 Subtask3:b=a−2Subtask 3 : b=a-2Subtask3:b=a−2 得到启发,只要首先满足三度点的个数要求,构造出一棵形如 Subtask3Subtask3Subtask3 的数据的树,再来考虑剩余的一度点。- 考虑如下情况:
1. 无解情况
可以注意到除了两个 111 度点,树上的点的平均度数为 222 。所以显然有 a<b+2a < b + 2a<b+2 的时候无解。
2. 剩下的一度点节点数为 111。
它既不能放在一度点,因为毫无作用,也不能放在二度点,因为会使二度点变成三度点,也不能放在三度点,因为会使三度点的个数减少。所以无法构造,直接输出 000 。
3. 剩下的一度点个数大于 111 。
直接往一号节点处放置即可。即往一号节点(唯一的二度点)添加儿子,它属于一个公用点,哪里需要往哪搬,它并不计入需要的一度点或三度点个数中,只要添加的不止一个儿子就行。
对于上面这种构造方法,其实也符合 Subtask1Subtask1Subtask1 的情况,那么最终的总的节点个数为 a+b+1a+b+1a+b+1 个点,只要有解就一定不会超过限制。时间复杂度 O(a+b)O(a+b)O(a+b) 。
- 考虑如下情况:
不知我的做法有没有问题,考场通过了,欢迎来hack。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
ll a,b;
int main()
{
// freopen("irises.in","r",stdin);
// freopen("irises.out","w",stdout);
cin>>a>>b;
if(a<b+2)
{
cout<<0;
return 0;
}
if(b==0)
{
if(a==0)
{
cout<<1;
return 0;
}
if(a!=3)
{
cout<<a+1<<endl;
for(int i=2;i<=a+1;i++)
{
cout<<1<<" "<<i<<endl;
}
return 0;
}
}
if(b==a-2)
{
ll cnt=0;
cout<<a+b+1<<endl;
for(int i=1;i<=a+b-1;i+=2)
{
if(cnt<a+b) cout<<i<<" "<<i+1<<endl,cnt++;
if(cnt<a+b) cout<<i<<" "<<i+2<<endl,cnt++;
}
return 0;
}
if(a-b-2<2)
{
cout<<0;
return 0;
}
ll cnt=0;
cout<<a+b+1<<endl;
for(int i=1;i<=b+b+2-1;i+=2)
{
if(cnt<b+b+2) cout<<i<<" "<<i+1<<endl,cnt++;
if(cnt<b+b+2) cout<<i<<" "<<i+2<<endl,cnt++;
}
cnt++;
for(int i=1;i<=a-b-2;i++)
{
cout<<1<<" "<<cnt+i<<endl;
}
return 0;
}