Blocks (POJ - 3734)(矩阵快速幂)

Panda has received an assignment of painting a line of blocks. Since Panda is such an intelligent boy, he starts to think of a math problem of painting. Suppose there are N blocks in a line and each block can be paint red, blue, green or yellow. For some myterious reasons, Panda want both the number of red blocks and green blocks to be even numbers. Under such conditions, Panda wants to know the number of different ways to paint these blocks.

Input
The first line of the input contains an integer T(1≤T≤100), the number of test cases. Each of the next T lines contains an integer N(1≤N≤10^9) indicating the number of blocks.

Output
For each test cases, output the number of ways to paint the blocks in a single line. Since the answer may be quite large, you have to module it by 10007.

Sample Input
2
1
2
Sample Output
2
6

之前做过一道关于斐波那契数列的一道题(POJ-3070),非常相似(我指的方法),如果n非常大,即使是线性时间也会超时,题目的提示是矩阵,进行对数时间的加速,效率非常高,那是我第一次见识到线性代数的威力,可是那个时候没有仔细想其中的原理,今天突然想起来,就研究了一下(矩阵快速幂的应用要比我想象中的还要广)

比如这道题,题设要求红色(r)和绿色(g)的个数在n个的块中的颜色都是得偶数(even),那么在这种条件下一共有多少种不同的方案。
我们设三种递推关系
r和g都是偶数 :ai
r和g都是奇数:bi
r和g中一奇一偶:ci(i为block的个数)
因为一共就只有这三种情况,没有在多的了
假设我们在i的基础上再加一个,即我们能否在已知i的基础上推出i和i+1的关系式。
其实已经很显然了
a[i+1]=2*a[i]+c[i]
b[i+1]=2*b[i]+c[i]
c[[i+1]=2*a[i]+2*b[i]+2*c[i]
然后我们用矩阵描述
大致形式与斐波那契数列那倒题一致
a[i+1] 2 0 1 a[i]
b[i+1]= 0 2 1 *b[i]
c[i+1] 2 2 2 c[i]
然后我们就可以定义 矩阵m=
2 0 1
0 2 1
2 2 2
矩阵 k=
1
0
0

a[n]
b[n]=m^n* k
c[n]
代码实现:

import java.util.Scanner;

public class Main 
{
    public static void main(String[]args)
    {
        Scanner sc=new Scanner(System.in);
        int t=sc.nextInt();
        M m=new M();
        m.a[0][0]=2;
        m.a[0][1]=0;
        m.a[0][2]=1;
        m.a[1][0]=0;
        m.a[1][1]=2;
        m.a[1][2]=1;
        m.a[2][0]=2;
        m.a[2][1]=2;
        m.a[2][2]=2;//矩阵m的初始化
        M o=new M();
        o.a[0][0]=1;
        o.a[1][1]=1;
        o.a[2][2]=1;//单位矩阵的初始化
        while((t--)>0)
        {
            int n=sc.nextInt();
            M k=o.copy();//一开始k的值为单位矩阵
            M l=m.copy();
            while(n>0)
            {
                if((n&1)==1)
                {
                    k=k.muip(l);
                }
                l=l.muip(l);
                n>>=1;//一直到这里的形式和常数矩阵快速幂非常相似,只不过我们操作的对象是矩阵而已
            }
            System.out.println(k.a[0][0]);
        }
    }

}
class M//按照要求定义3×3的矩阵
{
    long a[][]=new long[3][3];
    M muip(M x)//按照课本描述(对,就是课本hh)定义矩阵乘法
    {
        M m=new M();
        for(int i=0;i<3;i++)
            for(int j=0;j<3;j++)
            {
                m.a[i][j]=(a[i][0]*(x.a[0][j]%10007)+
                a[i][1]*(x.a[1][j]%10007)+
                a[i][2]*(x.a[2][j]%10007))%10007;//因为要对10007的模,我们只要这里直接实现即可
            }
        return m;
    }
    M copy()//矩阵的的复制
    {
        M m=new M();
        for(int i=0;i<3;i++)
            for(int j=0;j<3;j++)
            {
                m.a[i][j]=a[i][j];
            }
        return m;
    }
}

我们总结一下
1.对于矩阵m,实际上是系数矩阵
2.矩阵的应用可以是单一关系(如F[n]=F[n-1]+F[n-2)也可以是混合关系(如 a[n]=b[n-1]+c[n-1])
3.理论上所有的递推关系都可以用矩阵来统一描述和解决
4.如果题设要求给的n的数量级很大,一般得是用矩阵快速幂

peace&love

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值