UPCOJ 4333

来源:互联网 发布:mac新建txt 编辑:程序博客网 时间:2024/06/15 07:24

链接:

  http://exam.upc.edu.cn/problem.php?id=4333


题目:

题目描述

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?

输入

There are no more than 5000 test cases.
Each test case only contains one positive integer n(1 ≤ n ≤ 1018) in a line.

输出

For each test cases, output the answer mod 1000000007 in a line.

样例输入

1
2

样例输出

1
5


题意:

  用没有数量限制2×11×2的矩形去铺一块4×n的矩形,有多少种方法。


思路:

  先写了个DFS暴力打出n在区间[1,10]内对应的答案。

bool book[7][1007];bool findpos(int &x, int &y) {    for(int i=1 ; i<=4 ; i++) {        for(int j=1 ; j<=n ; j++) {            if(!book[i][j]) {                x = i, y = j;                return false;            }        }    }    return true;}void dfs(int x, int y) {    if(!book[x+1][y] && x<4) {        book[x][y] = book[x+1][y] = true;        int newx, newy;        if(findpos(newx, newy)) {            book[x][y] = book[x+1][y] = false;            cnt++;            return ;        }        dfs(newx, newy);        book[x][y] = book[x+1][y] = false;    }    if(!book[x][y+1] && y<n) {        book[x][y] = book[x][y+1] = true;        int newx, newy;        if(findpos(newx, newy)) {            book[x][y] = book[x][y+1] = false;            cnt++;            return ;        }        dfs(newx, newy);        book[x][y] = book[x][y+1] = false;    }}

  得到1 5 11 36 95 281 781 2245 6336 18061这前十个答案。

  然后觉得有一个边长是常数4,就写了五层for循环确定ans[i]与前四项和一个常数之间的系数关系,得到:ansi=ansi1+5×ansi2+ansi3ansi4+0,然后想到矩阵快速幂,容易得到:

1100501010011000×ansn1ansn2ansn3ansn4=ansnansn1ansn2ansn3

  需要注意的一点是,因为有一个系数是1,所以在矩阵乘法的过程中,在两两相加的时候要再加上一个mod之后再取模,不然的话有可能出现一个小的正数加上一个大的负数的情况。


实现:

#include <bits/stdc++.h>#define ll long longusing namespace std;const int maxn = 4;ll Matrixsize = 4, mod = int(1e9)+7, n;struct Matrix {    ll m[maxn][maxn];    Matrix(ll i = 0) {        memset(m, 0, sizeof m);        if (i == 1)            for (ll I = 0; I < Matrixsize; I++) m[I][I] = 1;    }    Matrix operator * (const Matrix tmp) const {        Matrix ret;        long long x;        for(ll i=0 ; i<Matrixsize ; i++)            for(ll j=0 ; j<Matrixsize ; j++) {                x=0;                for(ll k=0 ; k<Matrixsize ; k++)                    x+=(m[i][k] * tmp.m[k][j] + mod) % mod;                ret.m[i][j] = int(x % mod);            }        return ret;    }    Matrix qpow(long long n) {        Matrix ret = 1, tmp = *this;        while (n > 0) {            if (bool(n & 1)) ret = ret * tmp;            tmp = tmp * tmp;            n >>= 1;        }        return ret;    }};int main() {#ifndef ONLINE_JUDGE    freopen("../in.txt", "r", stdin);    printf("init! init! init!\n");#endif    Matrix 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;}