zoukankan      html  css  js  c++  java
  • POJ 3734 Blocks(矩阵快速幂+矩阵递推式)

    题意:个n个方块涂色, 只能涂红黄蓝绿四种颜色,求最终红色和绿色都为偶数的方案数。

    该题我们可以想到一个递推式 。   设a[i]表示到第i个方块为止红绿是偶数的方案数, b[i]为红绿恰有一个是偶数的方案数, c[i]表示红绿都是奇数的方案数。

    那么有如下递推可能:

    递推a[i+1]:1.到第i个为止都是偶数,且第i+1个染成蓝或黄;2.到第i个为止红绿恰有一个是奇数,并且第i+1个方块染成了奇数对应的颜色。

    递推b[i+1]:1.到第i个为止都是偶数,且第i+1个染成红或绿;2.到第i个为止红绿恰有一个是奇数,并且第i+1个方块染成了蓝或黄;3.到第i个方块为止红火绿都是奇数,并且第i+1个染成红火绿。

    递推c[i+1]:1.到第i个为止红绿恰有一个是奇数, 并且第i+1个方块染成偶数对应的颜色;2.到第i个为止红绿都是奇数,并且第i+1个方块染成蓝或黄。

    即a[i+1] = 2*a[i] + b[i];

        b[i+1] = 2*a[i] + 2*b[i] + 2*c[i];

        c[i+1] = b[i] + 2*c[i];

    因为DP的过程中,每一步都是在重复上一个过程, 所以可以用矩阵相乘来优化算法。

    将上述递推式写成矩阵相乘的形式:

    { a[i] }      {2  1  0}^i{a[0] }

    { b[i] }  = {2  2  2}   {b[0] }

    { c[i] }     {0  1  2}   {c[0] }

    然后用矩阵快速幂就可以了。

    AC代码

    #include<stdio.h>
    #include<string.h>
    #define mod 10007
    struct Mat
    {
        long long  mat[3][3];
    };
    
    Mat operator * (Mat a,Mat b)
    {
        int n=3;
        Mat c;
        c.mat[2][2]=c.mat[2][0]=c.mat[2][1]=c.mat[0][0]=c.mat[0][1]=c.mat[0][2]=c.mat[1][0]=c.mat[1][1]=c.mat[1][2]=0;
        int i,j,k;
        for(k =0 ; k < n ; k++)
        {
            for(i = 0 ; i < n ;i++)
            {
                if(a.mat[i][k]==0) continue;//优化
                for(j = 0 ;j < n ;j++)
                {
                    if(b.mat[k][j]==0) continue;//优化
                    c.mat[i][j] = (c.mat[i][j]+(a.mat[i][k]*b.mat[k][j])%mod)%mod;
                }
            }
        }
        return c;
    }
    Mat operator ^(Mat a,int k)
    {
        int n=3;
        Mat c;
        int i,j;
        for(i =0 ; i < n ;i++)
            for(j = 0; j < n ;j++)
            c.mat[i][j] = (i==j);
        for(; k ;k >>= 1)
        {
            if(k&1) c = c*a;
            a = a*a;
        }
        return c;
    }
    int main( )
    {
        long long n;
        int t;
       scanf("%d",&t);
        while(t--)
        {
            scanf("%lld",&n);
            Mat A;
            A.mat[0][0]=2;A.mat[0][1]=1;A.mat[0][2]=0;
            A.mat[1][0]=2;A.mat[1][1]=2;A.mat[1][2]=2;
            A.mat[2][0]=0;A.mat[2][1]=1;A.mat[2][2]=2;
            Mat ans=A^n;
            printf("%lld
    ",ans.mat[0][0]);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    五个知识体系之-Linux常用命令学习
    测试职业生涯中,五个知识体系
    英语:真正有效的英语学习心得,把英语当母语学习!(转载)
    侧滑面板(对viewGroup的自定义)
    安卓程序员要拿到5000和1w的薪资,分别需要掌握哪些技术?
    轻巧级记事本的开发
    web.xml 中的listener、 filter、servlet 加载顺序及其详解
    如何向android studio中导入第三方类库
    【NPR】卡通渲染
    线程池原理及其实现
  • 原文地址:https://www.cnblogs.com/shuaihui520/p/9152549.html
Copyright © 2011-2022 走看看