HihoCoder 1873 Frog and Portal (思维)

题目传送门

时间限制:1000ms 单点时限:1000ms 内存限制:512MB

描述

A small frog wants to get to the other side of a river. The frog is initially located at one bank of the river (position 0) and wants to get to the other bank (position 200). Luckily, there are 199 leaves (from position 1 to position 199) on the river, and the frog can jump between the leaves. When at position p, the frog can jump to position p+1 or position p+2.

How many different ways can the small frog get to the bank at position 200? This is a classical problem. The solution is the 201st number of Fibonacci sequence. The Fibonacci sequence is constructed as follows: F1=F2=1;Fn=Fn-1+Fn-2.

Now you can build some portals on the leaves. For each leaf, you can choose whether to build a portal on it. And you should set a destination for each portal. When the frog gets to a leaf with a portal, it will be teleported to the corresponding destination immediately. If there is a portal at the destination, the frog will be teleported again immediately. If some portal destinations form a cycle, the frog will be permanently trapped inside. Note that You cannot build two portals on the same leaf.

Can you build the portals such that the number of different ways that the small frog gets to position 200 from position 0 is M?

输入

There are no more than 100 test cases.

Each test case consists of an integer M, indicating the number of ways that the small frog gets to position 200 from position 0. (0 ≤ M < 2^32)

输出

For each test case:

The first line contains a number K, indicating the number of portals.

Then K lines follow. Each line has two numbers ai and bi, indicating that you place a portal at position ai and it teleports the frog to position bi.

You should guarantee that 1 ≤ K, ai, bi ≤ 199, and ai ≠ aj if i ≠ j. If there are multiple solutions, any one of them is acceptable.

样例输入

0
1
5

样例输出

2
1 1
2 1
2
1 199
2 2
2
4 199
5 5

思路分析

题目大概的意思是说,有只青蛙要从第0个点到第200个点去,中途有1~199个点,其中它每次可以向前跳1步或者2步。而现在加一个条件,就是我们可以在一些地方放传送门,使得青蛙走到这个点的时候可以直接传送到目的点。题目询问从0到200有m种方案数的一种放置传送门的方法。

很多人被上面的斐波那契数列给绕晕了,用斐波那契来写是可以写的,但是个人感觉特别麻烦,所以想到种简单的一种方法:

首先,我们可以把问题理解成,我当前站在 p o s pos pos点,需要 m m m种方案到达终点,这样我们可以分类讨论:

  • 如果 m m m是偶数,那么我们该如何让方案数缩小一半呢?我们可以在 p o s + 1 pos+1 pos+1的位置建立一个到 p o s + 3 pos+3 pos+3的传送门,然后在 p o s + 2 pos+2 pos+2的地方建立一个到 p o s + 1 pos+1 pos+1的传送门,这样我们从 p o s pos pos p o s + 3 pos+3 pos+3的方案数是2种,那么问题就被分解成:我现在站在 p o s + 3 pos+3 pos+3点,需要 m 2 \frac{m}{2} 2m种方案到达终点

  • 如果 m m m是奇数的话,我们要想让 m m m变成可以用上面的东西进行分解的话,我们只需要在 p o s + 1 pos+1 pos+1处放置一个到199号点的传送门,然后跳到 p o s + 2 pos+2 pos+2号点上,这个问题就变成了:我现在站在 p o s + 2 pos+2 pos+2点,需要 m − 1 m-1 m1种方案到达终点

然后问题就被分解成不断的小问题啦!

最后,注意当 m = 1 m=1 m=1 m = 0 m=0 m=0的时候特判一下就OK了!

最最最最最最后,m要开 l o n g l o n g long long longlong!!!

Code:

#include 
using namespace std;
struct node{
	int x,y;
}a[500];

int main(){
	long long m;
	while (cin>>m){
		int cnt=0,pos=0;
		if (m==0){
			cout<<"2\n"<<"1 1\n"<<"2 1\n";
		}else{
			while (m!=0){
				if (m==1){
					a[++cnt].x=pos+1,a[cnt].y=199;
					a[++cnt].x=pos+2,a[cnt].y=pos+2;
					m/=2;
					break;
				}
				if (m%2==0){
					a[++cnt].x=pos+1,a[cnt].y=pos+3;
					a[++cnt].x=pos+2,a[cnt].y=pos+1;
					pos=pos+3;
					m/=2;
				}else {
					a[++cnt].x=pos+1,a[cnt].y=199;
					pos=pos+2;
					m--;
				}
			}
			cout<<cnt<<endl;
			for (int i=1;i<=cnt;i++)
				cout<<a[i].x<<" "<<a[i].y<<endl;
		}
	}
	return 0;
}


你可能感兴趣的:(acm)