Cat Virus

链接:Problem - C - Codeforces

In the cat country, any cat family can be regarded as a rooted tree. As we all know, a kind of zombie virus hides in all the cats' bodies. Therefore, a cat family may consist of cats and zombies. When a cat is born, it may become a zombie. If a cat becomes a zombie, all of its offspring will also become zombies.

Now given an integer K, you should construct a cat family with exactly K ways to mark the identities (cat or zombie) of members of this family. Two ways are considered different if and only if there is at least one member that is marked as a cat in one way and marked as a zombie in the other way.

Formally, the vertices in a rooted tree will be marked black or white, and if a vertex is marked black, all the vertices in its subtree should also be marked black. Given a rooted tree, it's easy to calculate the number of possible valid ways to mark the vertices in the tree. Your task is to construct a rooted tree with exactly K ways to mark your tree's vertices. Two ways are considered different if and only if there is at least one vertex such that in one way is marked black and marked white in the other way.

Input
The only line contains an integer K (2≤K≤2⋅1018) – the number of valid ways to mark the vertices in the tree.

Output
Let's denote the number of vertices of the tree you construct as n, and label the vertices from 1 to n where vertex 1 is the root.

The output should contain n lines. In the first line, print one integer n (1≤n≤105). In the each of the next n−1 lines, print two integers u,v (1≤u,v≤n,u≠v) describing an edge in your rooted tree.

It is guaranteed that at least one solution exists. If there are several possible valid solutions, you can print any of them.

input

5

output

3
1 2
1 3

题意:可以给一个树的每个节点涂上黑色和白色,当节点涂上黑色节点时,那它的所有子孙节点都只能是黑色,涂上白色时,它的子节点可以为任意颜色。给K种涂色方法,求能够刚好满足K种涂色方法的一颗树。

该题最开始想时,是弄一个每个节点只有一个子节点的树,每多一个方案就在下面加一个节点,但由于题目要求输出的节点数要小于100000,所以理所当然的wa了 ort... 
既然这种单枝树要用的节点太多,那就只能换种构建方法 。 

当只有一个节点时,只能涂黑色或白色,所以方案数为2。当该节点增加一个子节点时,则方案数+1。增加两个子节点,也就是一对兄弟节点时,方案数为 以左节点为根节点的方案数 乘以 以右节点为根节点的方案数 加一 (l*r+1)(+1是当根节点为黑色时的情况)。

所以我们可以把K逐步分解,当K为奇数并不为3时,在当前节点位置加上一对兄弟节点,并且(K-1)/2(因为只有一个节点时,涂色方案数是2,所以相当于2*r+1=K)(之所以不为3,是因为(l*r+1)>=5)。
为偶数或为3时,在当前节点位置加一个子节点,并且K --,重复以上操作,直到K=2为止 。

代码如下:

#include<iostream>
#include<vector>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
vector<PII> v; //用来记录点 
int main()
{

	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);
	LL K;
	cin >> K;
	int ans = 1; //当前所在节点,以及节点总数 
	while(K>2)
	{
		if(K&1) //K为奇数时 
		{
			if(K==3) v.push_back({ans ++, ans}); //K==3时,增加一个子节点 
			else //增加一对兄弟节点。 
			{
				ans += 2;
				v.push_back({ans-2, ans-1});
				v.push_back({ans-2, ans});
			}
			K >>= 1; //由于是向下整除,所以减一可以省略。 
		}
		else //K为偶数时 
		{
			K --;
			v.push_back({ans ++, ans});
		}
	}
	
	cout << ans << endl;
	for(auto &i: v) cout << i.first << " " << i.second << endl;
	return 0;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值