斐波那契数列 改1 3*N 骨牌覆盖 改1 hiho一下 第四十二周 递归不行 矩阵加速

题目1 : 骨牌覆盖问题·二

时间限制:10000ms

单点时限:1000ms

内存限制:256MB

描述

上一周我们研究了2xN的骨牌问题,这一周我们不妨加大一下难度,研究一下3xN的骨牌问题?
所以我们的题目是:对于3xN的棋盘,使用1x2的骨牌去覆盖一共有多少种不同的覆盖方法呢?
首先我们可以肯定,奇数长度一定是没有办法覆盖的;对于偶数长度,比如2,4,我们有下面几种覆盖方式:

提示:3xN骨牌覆盖

输入

第1行:1个整数N。表示棋盘长度。1≤N≤100,000,000

输出

第1行:1个整数,表示覆盖方案数 MOD 12357

样例输入
62247088
样例输出
4037
#include <iostream>
#include <vector>
using namespace std;
#define modnum 12357
typedef vector<long long> matrow;
typedef vector<matrow> mat;
mat build(long long x,long long y,long long a[])
{
    mat ans;
    for(long long i=0;i<x;i++)
    {
        ans.push_back(matrow());
        for(long long j=0;j<y;j++)
        {
            ans[i].push_back(a[i*y+j]);
        }
    }
    return ans;
}
mat multi(const mat mat1,const mat mat2)
{
    long long temp=0;
    long long rownum=mat1.size();
    long long colnum=mat2[0].size();
    long long nummul=mat1[0].size();
    mat ans;
    for(long long i=0;i<rownum;i++)
    {
        ans.push_back(matrow());
        for(long long j=0;j<colnum;j++)
        {
            temp=0;
            for(long long t=0;t<nummul;t++)
                temp+=mat1[i][t]*mat2[t][j];
            ans[i].push_back(temp%modnum);
        }
    }
    return ans;
}

int main()
{
    long long N;
    long long a[]={3,1,2,1};
    long long b[]={3,2};
    cin>>N;
	if(N%2==1){ cout<<0<<endl; return 0; }
    mat ans=build(2,1,b);
    mat temp=build(2,2,a);
    long long n=N/2-1;
    if(n==0)cout<<3<<endl;
    if(n==1)cout<<11<<endl;
    if(n!=1&&n!=0)
    {
		while(n)
		{
			if(n&1==1)
				ans=multi(temp,ans);
			temp=multi(temp,temp);
			n=n>>1;
		}
	}
	cout<<ans[0][0]<<endl;
    return 0;
}

  

这一期的问题和上一期的一样,也是使用矩阵乘法加速,

用Xn表示N的排列总数

用Tn表示N的特殊排列总数(特殊排列:最后一列有竖直骨牌如:n=2时 第二第三个骨牌。 n=4时2 4 6 7 8 10 11)

N+2的排列总数 = “N的排列总数 拼接上n=2时的排列” + “N的特殊排列  拼接上n=2时第一个骨牌  并进行微调”

( “N的特殊排列  接上n=2时第一个骨牌  并进行微调” 参见n=4时 4和8 ,通过n=4时 9和5调整获得 )

Xn+2=Xn*3+Tn

N+2的特殊排列=“N的排列总数,拼接上n=2时 2 3 骨牌”+ “N的特殊排列 ,拼接上n=2时第一个骨牌 并进行微调”

Tn+2=Xn*2+Tn

用矩阵表示:

|Xn+2m|    =   |3   1|    ^m-1    |3|

|Tn+2m|          |2   1|                 |2|

时间: 2024-10-12 08:19:26

斐波那契数列 改1 3*N 骨牌覆盖 改1 hiho一下 第四十二周 递归不行 矩阵加速的相关文章

c语言:写一个函数,输入n,求斐波拉契数列的第n项(5种方法,层层优化)

写一个函数,输入n,求斐波拉契数列的第n项. 斐波拉契数列:1,1,2,3,5,8...,当n大于等于3时,后一项为前面两项之和. 解:方法1:从斐波拉契数列的函数定义角度编程 #include<stdio.h> int fibonacci(int n) { int num1=1, num2=1, num3=0,i; if (n <= 2) { printf("斐波拉契数列的第%d项为:%d\n",n,num1); } else { for (i = 2; i <

Talking About斐波那契数列(三种实现方法)

一直学习数据结构和算法,虽然学的没有太好,但还是觉得应该做一些有意思的程序来实现以下~牛客网(大哥推荐,还有就是..不要问我大哥是谁~~)有剑指Offer系列很多的题目,不管是大神还是..应该去做一下,感受编程的魅力~~(首先承认自己还是有很多不足的地方,但尽量去完善每一行代码~)  废话少说,代码搞起~ import java.util.Scanner; /** * 现在要求输入一个整数n,请你输出斐波那契数列的第n项. * 斐波那契数列,又称黄金分割数列,指的是这样一个数列 0, 1, 1,

一起talk C栗子吧(第四回:C语言实例--斐波那契数列)

各位看官们,大家好,从今天开始,我们讲大型章回体科技小说 :C栗子,也就是C语言实例.闲话休提, 言归正转.让我们一起talk C语言实例吧! 看官们,上一回中咱们说的是求阶乘的例子,这一回咱们说的例子是:斐波那契数列. 看官们,斐波那契数列是以数学家斐波那契数列的姓来命名的.斐波那契数列的定义:数列的第0项和第1项 为1,第n项为第n-1项和第n-2项的和.用数学公式表示出来就是:f(n)=f(n-1)+f(n-2),其中(n>1),f(n)=1;(n=0,1). 看官们,我在程序中使用了递归

【笔试】27、斐波那契数列

写一个函数,输入n,求斐波那契数列的第n项.斐波那契数列的定义如下 我们的第一反应是使用递归来做,但是实际上递归的效率非常之低 public static long TiaoJi(int n) { if(n <= 0) return 0; if(n == 1) return 1; return TiaoJi(n - 1) + TiaoJi(n - 2); } 其实我们可以用循环 /** *题目:1.写一个函数,输入n,求斐波那契数列的第n项. * 2.一只青蛙一次可以跳上1级台阶,也可以跳上2级

P1962 斐波那契数列

传送门 斐波那契数列 看一眼果断递推 f[ i ] = f[ i-1 ] + f[ i-2 ] 嘛 数据一看.. 好像不行.... 那就矩阵优化一下嘛 最基础的矩阵乘法嘛 (不懂先学一下 矩阵乘法 吧) 稍微想一想: 设矩阵为 A 那么矩阵 [  f[i-2]   ,   f[i-1]  ] * A 要等于 [  f[i-1]   ,   f[i]  ](即要等于 [ f[i-1]   ,   f[i-1]+f[i-2]  ]) 在纸上稍微画一下就得到 A 了 (随便挂一下当初学构造矩阵的链接:

斐波那契数列的最优算法(O(logN))

相信大家都对斐波那契数列已经相当的熟悉了,最多两分钟就可以写出来以下时间复杂度为O(N)的代码: //递归实现 long long fib(int n) { if (n =1 || n== 2) { return 1; } return (fib(n - 2) + fib(n - 1)); } 或者是这样的时间复杂度为O(N),空间复杂度为O(1): //优化一:时间复杂度为O(N) long long fib(int n) { long long* fibarry = new long lon

C语言算法:完善当年自编的k阶斐波那契数列

以下为大二时候的日志回放:" 题目扩展到K阶, k阶斐波那契数列, 1阶(即k=1):1.1.1.1.1.1.1.-- a0=a[1-1]=1,a1=1,a2=1,a3=1,a4=1,a5=1,a6=1-- 3阶(k=3):0.0.1.1.2.4.7..... a0=0,a1=0,a2=a[3-1]=1,a3=0+0+1=1,a4=0+1+1=2,a5=1+2+4=7 4阶:0.0.0.1.1.2.4.8.15.27-- a0=0,a1=0,a2=0,a3=a[4-1]=1,a4=1,a5=2,

关于“斐波那契数列”的编程

关于"斐波那契数列"的编程 今天上网看到一个有关"斐波那契数列"的数学概念.自己学习编程时间也不短了,就借这个东东练习一下. 斐波那契数列,又称黄金分割数列,指的是这样一个数列:1.1.2.3.5.8.13.21.--在数学上,斐波纳契数列以如下被以递归的方法定义:F0=0,F1=1,Fn=F(n-1)+F(n-2)(n>=2,n∈N*)(来自百度) 一开始,我编程的代码如下: function fbnq($num) { if ($num == 0) { re

LintCode-查找斐波纳契数列中第 N 个数

题目: 查找斐波纳契数列中第 N 个数. 所谓的斐波纳契数列是指: 前2个数是 0 和 1 . 第 i 个数是第 i -1 个数和第 i -2 个数的和. 斐波纳契数列的前10个数字是: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34 ... 注意事项 The Nth fibonacci number won't exceed the max value of signed 32-bit integer in the test cases. 样例 给定 1,返回 0 给定 2,返