1. 程式人生 > >HihoCoder - 1873 2018ICPC北京站 D. Frog and Portal(構造)

HihoCoder - 1873 2018ICPC北京站 D. Frog and Portal(構造)

描述

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 < 232)

輸出

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 0 這個位置跳到 200 200 這個位置,他的起始位置為 0 0 .

青蛙每次可以向後跳 1 1 步或者 2 2 步,現在你可以給某個點放置一個傳送門,規定傳送門的起始和終止位置,那麼青蛙到達這個點後會從傳送門的起點瞬移到傳送門的終點,規定一個點最多隻能放置一個傳送門,如果一個傳送門的終點有一個傳送門,那麼青蛙可以連續傳送。

現在給出你一個方案數 M M ,你需要在這個座標軸上放置傳送門,使得青蛙從 0 0 200 200 這個位置的方案數恰好為 M M

構造題,假設當前青蛙所在位置為 x x ,因為他每次可以向後跳1或2步,那麼構造兩個門(x,x+2),(x+1,x),這樣無論青蛙怎麼跳,最後都會停在x+2這個位置上。那麼方案數就變成了原來的一半。

所以我們可以根據 M M 的奇偶性,當 M M 為偶數的時候就構造(x,x+2),(x+1,x)使得方案數變成原來的一半,當 M M 為奇數的時候,就可以構造從當前點直接連到199,(x,199),使得方案數減一,那麼方案數就變成了偶數,按照原來的方法繼續構造即可,一直到方案數為1時,直接給當前位置連線到199即可。

程式碼

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll, ll> pir;
int main()
{
    ll n;
    while (~scanf("%lld", &n))
    {
        if (n == 0)
            printf("2\n1 1\n2 1\n");
        else if (n == 1)
            printf("2\n1 199\n2 2\n");
        else
        {
            vector<pir> v;
            ll now = 1;
            while (n != 1)
            {
                if (n & 1)
                {
                    v.push_back(pir(now, 199));
                    now += 2;
                    v.push_back(pir(now, now + 2));
                    v.push_back(pir(now + 1, now));
                    now += 3;
                }
                else
                {
                    v.push_back(pir(now, now + 2));
                    v.push_back(pir(now + 1, now));
                    now += 3;
                }
                n >>= 1;
            }
            v.push_back(pir(now - 1, 199));
            printf("%lld\n", v.size());
            for (auto ans : v)
                printf("%lld %lld\n", ans.first, ans.second);
        }
    }
    return 0;
}