D - Frog and Portal HihoCoder - 1873 -Fibonacci 性质

  • D - Frog and Portal

  •  HihoCoder - 1873 
  • 题意:给你一个坐标轴,有一个青蛙,要从0这个位置跳到200 这个位置,他的起始位置为0 
  • 青蛙每次可以向后跳1 步或者2 步,现在你可以给某个点放置一个传送门,规定传送门传送位置。
  • 那么青蛙到达这个点后会从传送门的起点瞬移到传送门的终点,规定一个点最多只能放置一个传送门,
  • 如果一个传送门的终点有一个传送门,那么青蛙可以连续传送。现在给出你一个方案数M,
  • 你需要在这个坐标轴上放置传送门,使得青蛙从0 到200这个位置的方案数恰好为M 
  • 思路:猜测通过不加传送门的Fibonacci种类数,来凑出M,但是最初思路是搜索找到能够求和为M的数字
  • TLE了。然后了解到Fibonacci性质任何一个正数都可以由Fibonacci求和得到,所以可以从较大的Fibonacci数字往下
  • 比M小的就减掉,一定能减到0,把那些Fibonacci数的下标存下来,接下来就是构造了,如果通过那些下标出直接连到199
  • 那么种类数加起来恰好为M,这种思路是不对的,例如 选择了 下标 1 和 3的位置,M为4原来相加种类确实为4,但是由于
  • 在1位置上设置了传送门那么到达3的方式也就发生了改变,所以这种方式是错误的,既然从前面放置有影响那我们考虑一下用
  • 后面的来凑够M种,以200为起点往回计算Fibonacci数,那么他们下标记录的就是从每个位置到达200的种类数,
  • 这样只要我们从前面能够唯一的到达那些个位置就能保证种类数恰好为M,为了保证这个唯一,前面间隔着放即可
  • 从1-3-5--- 这样从位置0开始达到1是唯一的到达3也是唯一的同理后面的也都唯一,通过这些唯一的位置传送过去之后
  • 再根据传送到的那些位置到达终点的种类数相加恰好为M,所以问题就解决了,——感谢田甜姐提供的思路
  • #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define maxn 182
    ll a[maxn],n;
    vector<int>p;
    void init()
    {
        a[1]=1;
        a[2]=2;
        for(int i=3; i<=72; i++)
            a[i]=a[i-1]+a[i-2];
    }
    int main()
    {
        init();
        while(~scanf("%lld",&n))
        {
            p.clear();
            if(n==0)
            {
                printf("2\n1 1\n2 1\n");
                continue;
            }
            for(int i=70; i>=1; i--)
            {
                if(n==0)break;
                if(a[i]<=n)
                {
                    n-=a[i];
                    p.push_back(i);
                }
            }
            int len=p.size();
            printf("%d\n",len+1);
            for(int i=1,j=len-1; j>=0; i+=2,j--)
            {
                printf("%d %d\n",i,200-p[j]);
                if(j==0)
                    printf("%d %d\n",i+1,i+1);
            }
        }
        return 0;
    }

猜你喜欢

转载自blog.csdn.net/BePosit/article/details/84196499