HDU2842 Chinese Rings

来源:互联网 发布:appbook for mac 编辑:程序博客网 时间:2024/06/05 19:41

HDU2842(不水)

英文版原题

题目描述:一根木棒上有n个环(n<=10^9) 第一个环可以随意取下或者放上 如果前k个环都不在棒子上,且第k+1个环在棒子上,则你可以取下或放上第k+2个环 给出n,求最少需要多少步可以取完棒子上的环?

思路:

  1. 设f[n]数组表示取下n个环所需最小次数;
    1. 若想让第n个环被取下,那么前(n-2)个都要被取下,第(n-1)要挂在环上;这时所需次数为f[n-2]+1;
    2. 考虑第(n-1)个环还未取下;而取下第(n-1)个环需要第(n-2)个环挂上,取下第(n-2)个环需要第(n-3)个环挂上…即先要把前(n-2个都取下来);还有f[n-1]它自己;以此类推,取下第(n-1)个环需要次数为f[n-2]+f[n-2];
    3. 合并得到递推公式为:f[n] = f[n-1] + 2 * f[n-2] + 1;

然后有个矩阵相乘,每次换值(有点像DP)

矩阵乘法 规则+理解

菲波那切数列的递推理解
菲波那切数列的递推理解1
菲波那切数列的递推理解2

类似于斐波那契,本题的递推公式为
A:
| f[n] |
| f[n-1] |
| 1 |
B:
| 1 2 1 |
| 1 0 0 |
| 0 0 1 |
C:
| f[n-2]|
| f[n-1]|
| 1 |

A=B*C
就这样
贴上翻找到的 AC代码:
大神的代码

#include<stdio.h>#include<stdlib.h>#include<string.h>#define size 3#define mod 200907struct Mat{long long num[size][size];};Mat init,r;//定义全局变量;void InitMat()//初始化全局变量函数{    int i,j;    for (i=0;i<size;i++)        for (j=0;j<size;j++)            r.num[i][j] = init.num[i][j] = 0;            r.num[1][0] = r.num[2][0] = init.num[0][0]=init.num[0][2]=init.num[1][0]=init.num[2][2]=1;            r.num[0][0] = init.num[0][1]= 2;}Mat mul(Mat m,Mat r)//矩阵相乘{    Mat c;    memset(c.num,0,sizeof(c.num));    for (int i=0;i<size;i++)    {        for (int j=0;j<size;j++)        {            c.num[i][j] = 0;            for(int k=0;k<size;k++)            c.num[i][j]+=(m.num[i][k]*r.num[k][j])%mod;            c.num[i][j]%=mod;        }//矩阵相乘并赋给ans    }    return c;//返回最后的值}Mat pow(Mat m,int k)//矩阵的乘方函数{    Mat ans;    memset(ans.num,0,sizeof(ans.num));//首先置为0    for(int i=0;i<size;i++)        for(int j=0;j<size;j++)            if(i==j) ans.num[i][j]=1;//置为单位矩阵    while(k)    {        if(k&1) ans = mul(ans,m);//开始矩阵的乘方        k >>= 1;        m = mul(m,m);    }    return ans;//返回所求矩阵}int main(){    int n;    InitMat();    while (scanf("%d",&n)!=EOF)    {        if(n==0) return 0;        if(n==1) printf("1\n");        else if(n==2) printf("2\n");            else            {                Mat multi=pow(init,n-2);                Mat t=mul(multi,r);                printf("%lld\n",t.num[0][0]);            }    }    return 0;}

1 0
原创粉丝点击