zoukankan      html  css  js  c++  java
  • 纪中23日c组T3 2161. 【2017.7.11普及】围攻 斐波那契数列

    2161. 围攻

    (File IO): input:siege.in output:siege.out

    时间限制: 1000 ms  空间限制: 262144 KB  具体限制  

    Goto ProblemSet

    题目描述

     经过刘邦的严密缉查,项羽的位置也就水落石出了。刘邦便趁机集合军队,进行对项羽的围攻。为了增加胜率,张良研究出一种全新的战法,目的就是一举打败难缠的项羽。
      这种军队共有N个单位,一个接着一个排成一排,每个单位可以是士兵,或者是战车,这样的组合可以爆发出意想不到的强大战斗力;但有一点,两辆战车不能相邻,否则会发生剐蹭等不好的事故。刘邦希望知道这N个单位的军队都多少种不同的排列方法,以便在战场中随机应变。两种军队的排列方法是不同的,当且仅当某一个单位对应不同,如:第i位这种是士兵,那种是战车……

    输入

     输入仅一行,一个整数N。

    输出

     输出仅一行,一个整数,表示排列的方案数。
     答案对 10^8+7 取模

    样例输入

    3

    样例输出

    5

    数据范围限制

     对于30%的数据:N≤15;
      对于70%的数据:N≤10^6;
      对于100%的数据:N≤10^18。

    提示

    样例解释
    以0表示士兵,1表示战车,则全部方案如下:000,100,010,001,101。

    Solution

    这道题是什么题?组合?数列?暴力枚举?搜索剪枝?

    先打个表压压惊……

    Algorithm1

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<map>
    #include<set>
    #include<queue>
    #include<vector>
    #define IL inline
    #define re register
    using namespace std;
    
    long long n,ans;
    IL void dfs(int depth,bool last)
    {
        if(depth>=n) {
            ans++;
            return;
        }
        if(!last) dfs(depth+1,1);
        dfs(depth+1,0);
    }
    int main()
    {
    //    freopen("siege.in","r",stdin);
    //    freopen("siege_table.out","w",stdout);
        for(n=1;n<=50;n++)
        {
            cout<<"n="<<n<<endl;
            ans=0;
            dfs(0,0);
            cout<<ans<<endl;
        }
        return 0;
    }
    table

    打表找规律,暴力出奇迹

    n=1
    2
    n=2
    3
    n=3
    5
    n=4
    8
    n=5
    13
    n=6
    21
    n=7
    34
    n=8
    55
    n=9
    89
    n=10
    144
    n=11
    233
    n=12
    377
    n=13
    610
    n=14
    987
    n=15
    1597
    n=16
    2584
    n=17
    4181
    n=18
    6765
    n=19
    10946
    n=20
    17711
    n=21
    28657
    n=22
    46368
    n=23
    75025
    n=24
    121393
    n=25
    196418
    n=26
    317811
    n=27
    514229
    n=28
    832040
    n=29
    1346269
    n=30
    2178309
    n=31
    3524578
    n=32
    5702887
    n=33
    9227465
    n=34
    14930352
    n=35
    24157817
    n=36
    39088169
    n=37
    63245986
    n=38
    102334155
    n=39
    165580141
    //速度太慢了,后略……

    好了,规律已找到,就是从2:1开始的斐波那契数列嘛

    (然而我并没有看到取模,于是在打完表后我就去写高精度了)

    证明呢?

    别问我……下午听完讲后再证明吧……

    Algorithm2

    当然是:

    暴力递推,边算边取模!

     1 #include<iostream>
     2 #include<algorithm>
     3 #include<cstdio>
     4 #include<cstring>
     5 #include<cmath>
     6 #include<map>
     7 #include<set>
     8 #include<queue>
     9 #include<vector>
    10 #define IL inline
    11 #define re register
    12 using namespace std;
    13 
    14 
    15 int main()
    16 {
    17 //    freopen("siege.in","r",stdin);
    18 //    freopen("siege.out","w",stdout);
    19     re unsigned int n,x=2,y=1,t,mo=1e8+7;
    20     cin>>n;
    21     while(--n)
    22     {
    23         t=x;
    24         x=x+y;
    25         y=t;
    26         while(x>=mo) 
    27             x-=mo;
    28     }
    29     printf("%d",x);
    30     return 0;
    31 }

    经过我多次实验,

    while+减法比%要快一倍

    register+局部变量比无register的全局变量也要快一点点

    每次只需要让x取模

    y和t也会变小

    以及

    这还是拿不到100分!

    Algorithm3

    好吧……我之前在洛谷上做过这道题的算法版(只是没有这些背景)

    然而,我忘记了……

    洛谷P1962 斐波那契数列

    对于100%的数据,n<=10^18,一些公式可以利用

    公式一

    f(2n)=f(n)^2-f(n-1)^2=(2f(n-1)+f(n))*f(n)

    公式二

    f(2n+1)=f(n+1)^2+f(n)^2

    证明

    下午再说……

    这样的话,只要对n进行二进制运算就可以了O(log(n))

    顺便加一个数组存已经计算好的斐波那契数,方便以后调用

    (不过10^18貌似存不下,考虑使用map)

     Code3

     1 #include<iostream>
     2 #include<algorithm>
     3 #include<cstdio>
     4 #include<cstring>
     5 #include<cmath>
     6 #include<map>
     7 #include<set>
     8 #include<queue>
     9 #include<vector>
    10 #define IL inline
    11 #define re register
    12 using namespace std;
    13 map<int,int>fbnq;
    14 long long mo=1e8+7;
    15 IL long long f(long long num)
    16 {
    17     if(num==1) return 1;
    18     if(num==2) return 1;
    19     if(num==3) return 2;
    20     if(fbnq.find(num)!=fbnq.end()) return fbnq[num];
    21     long long ans=0,n=num>>1;
    22     if(num&1)
    23     {
    24         ans=f(n+1)*f(n+1)%mo;
    25         ans+=f(n)*f(n)%mo;
    26     }
    27     else
    28     {
    29         ans=2*(f(n-1))%mo+f(n);
    30         ans%=mo;
    31         ans*=f(n);
    32         
    33     }
    34     ans%=mo;
    35     fbnq[num]=ans;
    36     return ans;
    37 }
    38 int main()
    39 {
    40 //    freopen("siege.in","r",stdin);
    41 //    freopen("siege.out","w",stdout);
    42     long long n;
    43     cin>>n;
    44     printf("%lld",f(n+2));
    45     return 0;
    46 }

    Attention

    最好都开long long以防还没取模就溢出了!

    还有许多细节可以优化

    但是我饿了

    纪中2019-08-23 12:32:06

    哎……

  • 相关阅读:
    web前端开发最佳实践--(笔记之JavaScript最佳实践)
    web前端开发最佳实践--(笔记一)
    HTML5及CSS3--freeCodeCamp(笔记一)
    javascript系列--函数(一)
    HTML5本地存储
    分享一些好用的设计网站
    .net面试问题总结
    ife_task10--弹性盒子
    WPF--搭建一个简单的demo
    信息技术文集
  • 原文地址:https://www.cnblogs.com/send-off-a-friend/p/11399227.html
Copyright © 2011-2022 走看看