题解 | #填数游戏#

填数游戏

http://www.nowcoder.com/practice/4cce3022cab449039f0075e6665d53c7

题意:

个格子,每个格子都可以填写四个整数,现在问你有多少种方案,使得最后所填数字中相同的偶数出现的次数也是偶数次?

解法一(动态规划,不可AC)

我们设:
    表示前个格子有偶数个和偶数个的方案数
    表示前个格子有偶数个和奇数个的方案数
    表示前个格子有奇数个和偶数个的方案数
    表示前个格子有奇数个和奇数个的方案数
一.  我们考虑转移
    (1)尝试从转移
        
        即
    (2)尝试从转移
        
        即
    (3)尝试从转移
        
    (4)尝试从转移
        前面有奇数个和奇数个,故无法只填写一个数字使满足有偶数个和偶数个,故无法转移

综上所述,

二. 我们考虑转移
    (1)尝试从转移
        
        即
    (2)尝试从转移
        
        即
    (3)尝试从转移
        前面有奇数个和偶数个,故无法只填写一个数字使满足有偶数个和奇数个,故无法转移
    (4)尝试从转移
        
        即
综上所述,
类似的,我们可以用上面的方法推导出:
    
    
最后,我们考虑答案:
    显然答案是有偶数个和偶数个的方案数,即
代码:
class Solution {
public:
    const int mod=1e9+7;
    //0 偶数个2偶数个4
    //1 偶数个2奇数个4
    //2 奇数个2偶数个4
    //3 奇数个2奇数个4
    int f[1000000001][4];
    int GetNumberOfSchemes(int n) {
        f[1][0]=2;//第1个格子0个2和0个4,两种方案:1、3
        f[1][1]=1;//第1个格子0个2和1个4,一种方案:4
        f[1][2]=1;//第1个格子1个2和0个4,一种方案:2
        f[1][3]=0;//第1个格子1个2和1个4,没有方案
        for(int i=2;i<=n;i++){
            f[i][0]=((f[i-1][0]*2%mod+f[i-1][1])%mod+f[i-1][2])%mod;//第一种
            f[i][1]=((f[i-1][0]+f[i-1][1]*2%mod)%mod+f[i-1][3])%mod;//第二种
            f[i][2]=((f[i-1][0]+f[i-1][2]*2%mod)%mod+f[i-1][3])%mod;//第三种
            f[i][3]=((f[i-1][1]+f[i-1][2])%mod+f[i-1][3]*2%mod)%mod;//第四种
        }
        return f[n][0];
    }
};
时间复杂度:,循环体执行了次,循环体内部是的,故总的时间复杂度是
空间复杂度:,我们需要开一个大小的数组,故总的空间复杂度是

解法二(矩阵快速幂)

根据解法一所得到的递推式,我们可以构造如下矩阵乘法式子:

根据矩阵乘法满足结合律,我们又可得:

于是我们就可以愉快地解决这道题了!
代码:
class Solution {
public:
    /**
     * 
     * @param n int整型 
     * @return int整型
     */
    static const int mod=1e9+7;
    struct mat{
        int A[4][4];
        inline mat(){
            memset(A,0,sizeof A);
        }
        inline mat operator * (const mat& other)const{//矩阵乘法
            mat ret;
            for(int i=0;i<4;i++){
                for(int j=0;j<4;j++){
                    for(int k=0;k<4;k++){
                        ret.A[i][j]+=1ll*A[i][k]*other.A[k][j]%mod;
                        ret.A[i][j]%=mod;//注意取余数
                    }
                }
            }
            return ret;
        }
    };
    mat ksm(mat a,int b){
        //矩阵快速幂算法
        mat ret;
        for(int i=0;i<4;i++)ret.A[i][i]=1;
        while(b){
            if(b&1){
                ret=ret*a;
            }
            a=a*a;
            b>>=1;
        }
        return ret;
    }
    int GetNumberOfSchemes(int n) {
        mat t;
        //初始化矩阵
        t.A[0][0]=2,t.A[0][1]=1,t.A[0][2]=1,t.A[0][3]=0;
        t.A[1][0]=1,t.A[1][1]=2,t.A[1][2]=0,t.A[1][3]=1;
        t.A[2][0]=1,t.A[2][1]=0,t.A[2][2]=2,t.A[2][3]=1;
        t.A[3][0]=0,t.A[3][1]=1,t.A[3][2]=1,t.A[3][3]=2;
        t=ksm(t,n-1);//求矩阵的n-1次方
        return ((1ll*2*t.A[0][0]%mod+t.A[0][1])%mod+t.A[0][2])%mod;//最后答案为f[n][0],模拟矩阵乘法计算答案
    }
};
时间复杂度:,其中代表矩阵乘法的时间复杂度,本题中,快速幂需要运算次,故总的时间复杂度为
空间复杂度:,矩阵的大小是的,故总的空间复杂度为

全部评论

相关推荐

球球别再泡了:坏,我单9要了14
点赞 评论 收藏
分享
不愿透露姓名的神秘牛友
11-26 18:54
说等下个版本吧的发呆爱好者很贪睡:佬最后去了哪家呀
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务