Covering HDU6185

26 篇文章 0 订阅
3 篇文章 0 订阅

Bob's school has a big playground, boys and girls always play games here after school.

To protect boys and girls from getting hurt when playing happily on the playground, rich boy Bob decided to cover the playground using his carpets.

Meanwhile, Bob is a mean boy, so he acquired that his carpets can not overlap one cell twice or more.

He has infinite carpets with sizes of 1×2 and 2×1, and the size of the playground is 4×n.

Can you tell Bob the total number of schemes where the carpets can cover the playground completely without overlapping?

InputThere are no more than 5000 test cases. Each test case only contains one positive integer n in a line. 1<=n<=10^18

题解:

先不谈这题的数据有多大,假设不大于10,那也不是掰掰手指头就能知道的,基本到了第4个就会有可能算错,如果你第三个就算错了我也没什么可说的,但是如果你第一第二个算错了,那就要打屁屁了,毕竟样例上有啊

首先,我们先写一个暴力,n不大于10的程序,很多种写法,我在这提供一种,对于以(i,j)为右下角 的点,有两种放法1×2 或者 2×1 ,然后往右下角dfs就行了,假设我们写出了这个程序,那么我们得出前十个数分别是1 5 11 36 95 281 781 2245 6336 18061

根据我们最朴素的算法经验,这题有点像个递推,很明显他就是,想这样方案数的个数很明显会和前面的方案数扯上点不干不净的关系,那么我们假设

f[i]=a*f[i-1]

f[i]=a*f[i-1]+b*f[i-2]

f[i]=a*f[i-1]+b*f[i-2]+c*f[i-3]

f[i]=a*f[i-1]+b*f[i-2]+c*f[i-3]+d*f[i-4]

…………………………

以此类推

然后将前十个数带进去验证,如果你们有强大的算术功底非要口算我也不拦着,最好是用计算机写个小程序搞一搞啦

这时候,我们就发现 第四个 式子存在可行的 a,b,c,d分别是 1,5,1,-1

也就是说 f[i]=1*f[i-1] + 5*f[i-2] +1*f[i-3] - 1*f[i-4],这时候直接递推需要O(n)的复杂度,那我们就需要用矩阵快速幂了!

我们把这个递推式写成矩阵的形式,(有人不会写,额,线代好好看看吧)

 1  5 -1  1          f[i-1]          f[i]

 1  0  0  0          f[i-2]          f[i-1]

 0  1  0  0          f[i-3]          f[i-2]

 0  0  1  0          f[i-4]          f[i-3]

我不会弄出那个框框,大家自己脑补以下吧

好了,这下以我们最朴素的线代知识 如果k是偶数 A^k=A^(k/2)  *   A^(k/2)  否则 A^k=A^(k/2)  *   A^(k/2)  *  k

不要问我这个表格用来干嘛,我也不知道

    
     
     
     
    

#include<cstdio>
#include <iostream>
#include <algorithm>
#include <string.h>
#include <string> 
#define ll long long
#define N 4 
using namespace std;
ll mod=int(1e9)+7, n;
struct arr {
    ll m[N][N];
    arr(ll i=0){
        memset(m,0,sizeof m);
        if (i==1)
            for (ll I= 0; I < N; I++) m[I][I]=1;
    }
    arr operator * (const arr tmp)const {
        arr ret;
        long long x;
        for(ll i=0;i<N;i++)
            for(ll j=0;j<N;j++) {
                x=0;
                for(ll k=0 ; k<N ; k++)
                    x+=(m[i][k] * tmp.m[k][j] + mod) % mod;
                ret.m[i][j]=int(x % mod);
            }
        return ret;
    }
    arr qpow(long long n) {
        arr ret=1, tmp=*this;
        while (n > 0) {
            if (bool(n & 1)) ret=ret * tmp;
            tmp=tmp * tmp;
            n >>= 1;
        }
        return ret;
    }
};

int main() {
    arr base1=0, base2=0;
    base1.m[0][0]=base1.m[0][2]=base1.m[1][0]=base1.m[2][1]=base1.m[3][2]=1;
    base1.m[0][3]=-1, base1.m[0][1]=5, base2.m[0][0]=1;
    base2.m[1][0]=0, base2.m[2][0]=1, base2.m[3][0]=1;
    while(~scanf("%lld",&n))
		printf("%lld\n",(base1.qpow(n)*base2).m[0][0]);
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值