POJ 3420

题意:给你4*n个格子,放满1*2的物体,问有多少种放法?

题解:我的做法比较麻烦 首先考虑f(n=1)=1 f(2)=5

后面的可以由前面的递推 例如 f(18)=f(17) + f(16) * 2 + (f(1)+f(3)+...+f(15)) * 2 + (f(0)+f(2)+f(4)+...+f(14)) * 3;

由之前的n加一整块得来

由于n比较大 所以用矩阵快速幂来搞 另外还要维护奇数前缀和与偶数前缀和  

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<vector>
#include<list>
#include<set>
#include<map>
#include<stack>
#include<queue>
#include<deque>
#define mem(x,y) memset(x,y,sizeof(x))
#define pb push_back
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll,ll> pii;
#define bug puts("===========");
#define zjc puts("");
const double pi=(acos(-1.0));
const double eps=1e-8;
const ll INF=1e18+10;
const ll inf=1e9+10;
const int maxn=100+10;
const int mod=1e9+7;
/*=======================================*/

/*=========================================
    矩阵运算
    乘法复杂度:O(N^3)
=========================================*/
const int Mn = 101;
const int Mm = 101;
typedef long long mytype;
#define wlhz %Mmod;
ll Mmod=1e9+7;
struct Matrix {
    int n, m;
    mytype a[Mn][Mm];
    void init() { memset(a, 0, sizeof(a)); }
    Matrix(int n=Mn,int m=Mm):n(n),m(m) {}
    void U(int Size){///将现有矩阵转换为一个同等大小的单位矩阵
        n=m=Size;
        init();
        for (int i = 0; i < n; i++) a[i][i] = 1;
    }
    Matrix unit() {///构造一个同等大小的单位矩阵
        Matrix tmp(n,n);
        tmp.init();
        for (int i = 0; i < n; i++) tmp.a[i][i] = 1;
        return tmp;
    }
    Matrix operator + (const Matrix &b) const {
        Matrix tmp(n,m);
        for (int i = 0; i < n; i++)
            for (int j = 0; j < m; j++) tmp.a[i][j] = (a[i][j] + b.a[i][j])wlhz
        return tmp;
    }
    Matrix operator - (const Matrix &b) const {
        Matrix tmp(n,m);
        for (int i = 0; i < n; i++)
            for (int j = 0; j < m; j++) tmp.a[i][j] = (a[i][j] - b.a[i][j])wlhz
        return tmp;
    }
    Matrix operator * (const Matrix &b) const {
        Matrix tmp(n,b.m); tmp.init();
        for (int i = 0; i < n; i++)
             for (int j = 0; j < m; j++)
                if (a[i][j])
                    for (int k = 0; k < b.m; k++)
                        tmp.a[i][k] = (tmp.a[i][k] + a[i][j] * b.a[j][k]) wlhz
        return tmp;
    }
    Matrix operator * (const mytype &b) const{
        Matrix tmp(n,m);
        for (int i = 0; i < n; i++)
             for (int j = 0; j < m; j++) {
                tmp.a[i][j] = a[i][j] * b wlhz
        }
        return tmp;
    }
    Matrix operator !() {///矩阵转置
        Matrix tmp(m,n);
        for (int i = 0; i < m; i++)
             for (int j = 0; j < n; j++)
            tmp.a[j][i] = a[i][j];
        return tmp;
    }
    friend Matrix pow(Matrix a, mytype b) {///矩阵快速幂
        Matrix tmp=a.unit();
        for (; b>0; b>>=1,a=a*a) if(b&1) tmp=tmp*a;
        return tmp;
    }
    void IN(){
        for(int i = 0; i < n; i++)
            for(int j = 0; j < m; j++) scanf("%lld",&a[i][j]);
    }
    void OT(){
        for(int i=0; i<n; i++)
            for(int j=0; j<m; j++) printf("%lld%c",a[i][j]," \n"[j==m-1]);
    }
};
Matrix A,B;
int dp[3];
int main()
{
    int n,m;
    while(~scanf("%d%d",&n,&m)&&n+m){
        Mmod=m;
        dp[1]=1; dp[2]=5;
        if(n<=2){
            printf("%d\n",dp[n]%m);
            continue;
        }
        A.n=1; A.m=5;
        A.a[0][0]=dp[2]; A.a[0][1]=dp[1]; A.a[0][2]=0; A.a[0][3]=0; A.a[0][4]=1;
        B.n=B.m=5;
        B.a[0][0]=1+4; B.a[0][1]=1; B.a[0][2]=1; B.a[0][3]=0; B.a[0][4]=0;
        B.a[1][0]=4+2; B.a[1][1]=4; B.a[1][2]=0; B.a[1][3]=1; B.a[1][4]=0;
        B.a[2][0]=2+3; B.a[2][1]=2; B.a[2][2]=1; B.a[2][3]=0; B.a[2][4]=0;
        B.a[3][0]=3+2; B.a[3][1]=3; B.a[3][2]=0; B.a[3][3]=1; B.a[3][4]=0;
        B.a[4][0]=3+2; B.a[4][1]=2; B.a[4][2]=0; B.a[4][3]=0; B.a[4][4]=1;
        A=A*pow(B,(n-1)/2);
        printf("%d\n",A.a[0][n%2]);

    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值