51Nod 1668 非010串

这是昨天上课ChesterKing dalao讲线代时的例题

当时看到这道题就觉得很水,记录一下后面两位的情况然后讨论一下转移即可

由于之前刚好在做矩阵题,所以常规的矩阵快速幂优化也很简单

好我们开始看题目

首先很容易考虑到所有的情况只和最后两位有关,所以我们设a,b,c,d表示结尾为10,11,01,00的方案数,然后每一次增加位数,都有新的a',b',c'd'这转移为:

  • a'=a

  • b'=b+c

  • c'=a+d

  • d'=a+d

然后这个就是尿性的矩阵优化了,我们可以稍加分析得出递推矩阵:

1 0 0 0
0 1 1 0
1 0 0 1
1 0 0 1

然后矩阵快速幂求之即可

CODE

#include<cstdio>
#include<cstring>
using namespace std;
typedef long long LL;
const int N=5,mod=1e9+7;
LL n;
struct Matrix
{
    int n,m;
    LL a[N][N];
    inline void Dt_init(void)
    {
        n=m=4; memset(a,0,sizeof(a));
        a[1][2]=a[2][2]=a[2][3]=a[3][1]=a[3][4]=a[4][1]=a[4][4]=1;
    }
    inline void cri_init(void)
    {
        n=m=4; memset(a,0,sizeof(a));
        a[1][1]=a[2][2]=a[3][3]=a[4][4]=1;
    }
    inline LL get_sum(void)
    {
        LL ans=0;
        for (register int i=1;i<=n;++i)
        for (register int j=1;j<=m;++j)
        ans=(ans+a[i][j])%mod;
        return ans;
    }
};
inline Matrix mul(Matrix A,Matrix B)
{
    Matrix C; C.n=A.n; C.m=B.m; memset(C.a,0,sizeof(C.a));
    for (register int i=1;i<=C.n;++i)
    for (register int j=1;j<=C.m;++j)
    for (register int k=1;k<=A.m;++k)
    C.a[i][j]=(C.a[i][j]+A.a[i][k]*B.a[k][j])%mod;
    return C;
}
inline Matrix quick_pow(Matrix A,LL p)
{
    Matrix T; T.cri_init();
    while (p)
    {
        if (p%2) T=mul(T,A);
        A=mul(A,A); p/=2;
    }
    return T;
}
int main()
{
    scanf("%lld",&n); Matrix A; A.Dt_init();
    if (n==1) { puts("2"); return 0; }
    if (n==2) { puts("4"); return 0; }
    A=quick_pow(A,n-2);
    printf("%lld",A.get_sum());
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/cjjsb/p/9088042.html
今日推荐