【51nod 1126】求递推序列的第N项 【矩阵快速幂】or【枚举找循环节】

来源:互联网 发布:我是拳王阿里 百度云 编辑:程序博客网 时间:2024/06/07 21:18

有一个序列是这样定义的:f(1) = 1, f(2) = 1, f(n) = (A * f(n - 1) + B * f(n - 2)) mod 7.
给出A,B和N,求f(n)的值。
Input
输入3个数:A,B,N。数字之间用空格分割。(-10000 <= A, B <= 10000, 1 <= N <= 10^9)
Output
输出f(n)的值。
Input示例
3 -1 5
Output示例
6

代码

#include<cstdio>#include<cstring>#include<cmath>#define LL long longusing namespace std;const int MAXN =100+10;const LL mod=7;struct Matrix{    LL a[MAXN][MAXN];    int r,c;};Matrix ori,res;LL a,b,n;void init(){    memset(res.a,0,sizeof(res.a));    res.r=2;res.c=2;    for(int i=1;i<=2;i++)  //将结果矩阵赋值为单位矩阵        res.a[i][i]=1;//单位矩阵A就是 [未知矩阵]B*A=B;    ori.r=ori.c=2;    ori.a[1][1]=a; ori.a[1][2]=b; ori.a[2][1]=1;// 初始化过度矩阵    ori.a[2][2]=0;}Matrix multi(Matrix x,Matrix y){    Matrix z;    memset(z.a,0,sizeof(z.a));    z.r=x.r;  z.c=y.c;      for(int i=1;i<=x.r;i++){        for(int k=1;k<=x.c;k++){            if(x.a[i][k]==0) continue;//小优化            for(int j=1;j<=y.c;j++)                 z.a[i][j]=(z.a[i][j]+(x.a[i][k]*y.a[k][j]%mod))%mod;        }    }    return z;}void Matrix_mod(int n){    while(n){        if(n&1) res=multi(ori,res);        ori=multi(ori,ori);        n>>=1;    }    Matrix it;it.r=2;it.c=1;   //  初始矩阵    it.a[1][1]=1; it.a[2][1]=1;    res=multi(res,it); // 初始矩阵*过渡矩阵的幂 就是结果     printf("%lld\n",(res.a[2][1]%mod+mod)%mod);//  因为有可能是负数,所以这样处理}int main(){        scanf("%lld%lld%lld",&a,&b,&n);        init();        Matrix_mod(n-1);  // 根据构造可知 n-1的幂才是f[n] ;     return 0;}

根据鸽巢原理,循环节最大就是49. 。
所以我们知道这个是有规律的,我们可以找到其循环节然后来处理。
这里写图片描述
还有就是负数的情况不能够考虑,所以就有了(()%7+7)%7的操作。
代码

#include <cstdio>int f[60];int main(){    int a,b,n;    scanf("%d%d%d",&a,&b,&n);    f[1] = f[2] = 1;    for (int i = 3;i <= 50; ++i){        f[i] = (a*f[i-1]+b*f[i-2])%7+7;        f[i]%=7;    }    int f1,f2,flag = 0;    for (int i = 1; i < 50; ++i){// 枚举找到循环节        for (int j = i+1;j<=50; ++j){            if (f[j]==f[i]&&f[j+1]==f[i+1]){                f1 = i;                f2 = j;                flag = 1;                break;            }        }        if (flag) break;    }    if (n<f1){        printf("%d\n",f[n]);    }else printf("%d\n",f[f1+(n-f1)%(f2-f1)]);    return 0;}
阅读全文
0 0
原创粉丝点击