快速矩阵幂+DFS构造矩阵+大数 ACdream1214 Nice Patterns Strike Back

传送门:点击打开链接

题意:告诉你矩阵大小是n*m,要求矩阵中不能有2*2的白色子矩阵或者黑色子矩阵,最后种类数模P

思路:如果不是大数,这道题还是非常有意思的。。对于专门卡C++的题目也是醉了...因为n太大了,而m最大也只有5,很明显是大数上的快速矩阵幂。

问题是如何构造出矩阵出来,之前做过骨牌的题目,就是利用DFS来构造的,感觉这道题在思路上是一样的,同样也是利用DFS先构造出矩阵

然后直接大数+快速矩阵幂撸一发就行了

#include<map>
#include<set>
#include<cmath>
#include<stack>
#include<queue>
#include<cstdio>
#include<string>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<functional>
#define FIN freopen("input.txt","r",stdin)
using namespace std;

const int matMX = 50;
const int DLEN = 4;
const int MAXN = 9999;

class BN {
public:
    int a[500];
    int len;

    BN(const int b = 0) {
        int c, d = b;
        len = 0;
        memset(a, 0, sizeof(a));
        while(d > MAXN) {
            c = d - (d / (MAXN + 1)) * (MAXN + 1);
            d = d / (MAXN + 1);
            a[len++] = c;
        }
        a[len++] = d;
    }
    BN(const char *s) {
        int t, k, index, L, i;
        memset(a, 0, sizeof(a));
        L = strlen(s);
        len = L / DLEN;
        if(L % DLEN) len++;
        index = 0;
        for(i = L - 1; i >= 0; i -= DLEN) {
            t = 0;
            k = i - DLEN + 1;
            if(k < 0) k = 0;
            for(int j = k; j <= i; j++) {
                t = t * 10 + s[j] - '0';
            }
            a[index++] = t;
        }
    }
    BN operator/(const int &b)const {
        BN ret;
        int i, down = 0;
        for(int i = len - 1; i >= 0; i--) {
            ret.a[i] = (a[i] + down * (MAXN + 1)) / b;
            down = a[i] + down * (MAXN + 1) - ret.a[i] * b;
        }
        ret.len = len;
        while(ret.a[ret.len - 1] == 0 && ret.len > 1) ret.len--;
        return ret;
    }
    bool operator>(const BN &T)const {
        int ln;
        if(len > T.len) return true;
        else if(len == T.len) {
            ln = len - 1;
            while(a[ln] == T.a[ln] && ln >= 0) ln--;
            if(ln >= 0 && a[ln] > T.a[ln]) return true;
            else return false;
        } else return false;
    }
    BN operator-(const BN &T)const {
        int i, j, big;
        bool flag;
        BN t1, t2;
        if(*this > T) {
            t1 = *this;
            t2 = T;
            flag = 0;
        } else {
            t1 = T;
            t2 = *this;
            flag = 1;
        }
        big = t1.len;
        for(i = 0; i < big; i++) {
            if(t1.a[i] < t2.a[i]) {
                j = i + 1;
                while(t1.a[j] == 0) j++;
                t1.a[j--]--;
                while(j > i) t1.a[j--] += MAXN;
                t1.a[i] += MAXN + 1 - t2.a[i];
            } else t1.a[i] -= t2.a[i];
        }
        t1.len = big;
        while(t1.a[t1.len - 1] == 0 && t1.len > 1) {
            t1.len--;
            big--;
        }
        if(flag) t1.a[big - 1] = 0 - t1.a[big - 1];
        return t1;
    }
    int operator%(const int &b)const {
        int i, d = 0;
        for(int i = len - 1; i >= 0; i--) {
            d = ((d * (MAXN + 1)) % b + a[i]) % b;
        }
        return d;
    }
};

LL mod;
struct Mat {
    int m, n;
    LL S[matMX][matMX];
    Mat(int a, int b) {
        m = a; n = b;
        memset(S, 0, sizeof(S));
    }
    Mat(int a, int b, LL w[][matMX]) {
        m = a; n = b;
        for(int i = 0; i < m; i++) {
            for(int j = 0; j < n; j++) {
                S[i][j] = w[i][j];
            }
        }
    }
};

Mat mat_mul(Mat A, Mat B) {
    Mat C(A.m, B.n);
    for(int i = 0; i < A.m; i++) {
        for(int j = 0; j < B.n; j++) {
            for(int k = 0; k < A.n; k++) {
                C.S[i][j] = (C.S[i][j] + A.S[i][k] * B.S[k][j]) % mod;
            }
        }
    }
    return C;
}

Mat Blank(int m, int n) {
    Mat ret(m, n);
    for(int i = 0; i < m; i++) {
        ret.S[i][i] = 1;
    }
    return ret;
}

Mat mat_pow(Mat A, BN b) {
    Mat ret = Blank(A.m, A.n);
    while(b > 0) {
        if(b % 2) ret = mat_mul(ret, A);
        A = mat_mul(A, A);
        b = b / 2;
    }
    return ret;
}

int m;
LL TB[matMX][matMX];
void DFS(int x, int y, int p) {
    if(p == m) {
        TB[x][y] = 1;
        return;
    }
    DFS(x << 1 | 1, y << 1, p + 1);
    DFS(x << 1, y << 1 | 1, p + 1);
    if(!p || (!((x & 1) && (y & 1)))) DFS(x << 1 | 1, y << 1 | 1, p + 1);
    if(!p || (!(!(x & 1) && !(y & 1)))) DFS(x << 1, y << 1, p + 1);
}

int main() {
    //FIN;
    char word[500];
    while(~scanf("%s%d%lld", word, &m, &mod)) {
        memset(TB, 0, sizeof(TB));
        DFS(0, 0, 0);

        BN n = BN(word);
        Mat s(1 << m, 1 << m, TB), fuck(1 << m, 1);
        for(int i = 0; i < (1 << m); i++) {
            fuck.S[i][0] = 1;
        }
        Mat res = mat_mul(mat_pow(s, n - 1), fuck);

        LL ans = 0;
        for(int i = 0; i < (1 << m); i++) {
            ans = (ans + res.S[i][0]) % mod;
        }
        printf("%lld\n", ans);
    }
    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-31 16:49:05

快速矩阵幂+DFS构造矩阵+大数 ACdream1214 Nice Patterns Strike Back的相关文章

UVa 11149 Power of Matrix (矩阵快速幂,倍增法或构造矩阵)

题意:求A + A^2 + A^3 + ... + A^m. 析:主要是两种方式,第一种是倍增法,把A + A^2 + A^3 + ... + A^m,拆成两部分,一部分是(E + A^(m/2))(A + A^2 + A^3 + ... + A^(m/2)),然后依次计算下去,就可以分解,logn的复杂度分解,注意要分奇偶. 另一种是直接构造矩阵,,然后就可以用辞阵快速幂计算了,注意要用分块矩阵的乘法. 代码如下: 倍增法: #pragma comment(linker, "/STACK:10

HDU 1575 &amp;&amp; 1757 矩阵快速幂&amp;&amp;构造矩阵入门

HDU 1575 Tr A Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 2912    Accepted Submission(s): 2167 Problem Description A为一个方阵,则Tr A表示A的迹(就是主对角线上各项的和),现要求Tr(A^k)%9973. Input 数据的第一行是一个T,表示有T组数据.每组

[POJ 3735] Training little cats (构造矩阵、矩阵快速幂)

Training little cats Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 9613   Accepted: 2296 Description Facer's pet cat just gave birth to a brood of little cats. Having considered the health of those lovely cats, Facer decides to make th

ZOJ2317-Nice Patterns Strike Back:矩阵快速幂,高精度

Nice Patterns Strike Back Time Limit: 20000/10000MS (Java/Others)Memory Limit: 128000/64000KB (Java/Others) Problem Description You might have noticed that there is the new fashion among rich people to have their yards tiled with black and white tile

HDU 4965 Fast Matrix Calculation (矩阵快速幂取模----矩阵相乘满足结合律)

http://acm.hdu.edu.cn/showproblem.php?pid=4965 利用相乘的可结合性先算B*A,得到6*6的矩阵,利用矩阵快速幂取模即可水过. 1 #include<iostream> 2 #include<stdio.h> 3 #include<iostream> 4 #include<stdio.h> 5 #define N 1010 6 #define M 1010 7 #define K 6 8 using namespa

CodeForces621E 快速矩阵幂优化dp

有时些候在用快速矩阵幂优化dp的时候,它的矩阵乘法是不那么容易被具体为题目背景的意思的,大多数时候难以理解矩阵之间相乘的实际意义,正如有时候我们不知道现在在做手头这些事情的意义,但倘若是因一个目标而去做的,正如快速矩阵幂最终会计算出答案一样,我们也最终会在这些不明意义的事情中实现目标. 题意:有 bb 个格子,每个格子有 nn 个数字,各个格子里面的数字都是相同的. 求从 bb 个格子中各取一个数字, 构成一个 bb 位数, 使得这个 bb 位数模 xx 为 kk 的方案数(同一格子内相同的数字

求幂大法,矩阵快速幂,快速幂模板题--hdu4549

hdu-4549 求幂大法.矩阵快速幂.快速幂 题目 M斐波那契数列 Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others)Total Submission(s): 6217 Accepted Submission(s): 1902 Problem Description M斐波那契数列F[n]是一种整数数列,它的定义如下: F[0] = a F[1] = b F[n] = F[n-1] *

快速幂算法(矩阵快速幂还不是很会。。日后会更新)

PS:转载,自己写的不如人家,怕误导.转载地址:http://www.cnblogs.com/CXCXCXC/p/4641812.html 首先,快速幂的目的就是做到快速求幂,假设我们要求a^b,按照朴素算法就是把a连乘b次,这样一来时间复杂度是O(b)也即是O(n)级别,快速幂能做到O(logn),快了好多好多.它的原理如下: 假设我们要求a^b,那么其实b是可以拆成二进制的,该二进制数第i位的权为2^(i-1),例如当b==11时   a^11=a^(2^0+2^1+2^3) 11的二进制是

hdu 1757 A Simple Math Problem 构造矩阵

题意:函数f(x), 若 x < 10 f(x) = x. 若 x >= 10 f(x) = a0 * f(x-1) + a1 * f(x-2) + a2 * f(x-3) + …… + a9 * f(x-10); 且 ai(0<=i<=9) 仅为 0 或 1 . 给定k,m,求f(k)%m; 思路:求一个递推函数的函数值,显然是矩阵快速幂,矩阵构造方法如下: #include<cstdio> #include<cstring> #include<al