zoukankan      html  css  js  c++  java
  • SGU 197.Nice Patterns Strike Back

    时间限制:0.5s

    空间限制:6M

    题意:

           给出长n(n<=10^100)和宽m(m<=5)的地面,铺上黑色和白色的地板,使得没有任意一个2*2大小的地面铺同种颜色的方案数是多少.

     

     

     

     

     

     

     

     

     

     

     

     

     


    Solution:

                 状态压缩,一个数字的对应为01分别代表铺白色和黑色地板,对于每一列有(1<<m)种状态.

                 我们可以构造一个矩阵,mat[i][j]代表,第一列是状态是i,第二列是j的方案数,显然mat[i][j]不是0就是1,而且很容易判断构造.

                 然后我们只要对这个矩阵进行快速幂运算,幂为(n-1),当然不要忘记取模,最后把mat所有元素加起来就是我们想要的答案了.

                 由于n比较大,所以要做大数的减一,和除以二的运算.

     

    code

    #include <iostream>
    #include <cstring>
    #include <string>
    using namespace std;
    struct Mat {
        int mat[100][100];
    } mx;
    int pow[109];
    int n, m, mod, len;
    Mat operator * (Mat a, Mat b) {
        Mat c;
        memset (c.mat, 0, sizeof c.mat);
        for (int k = 0; k <  (1 << m); k++)
            for (int i = 0; i <  (1 << m); i++)
                for (int j = 0; j <  (1 << m); j++)
                    (c.mat[i][j] += (a.mat[i][k] * b.mat[k][j]) % mod) %= mod;
        return c;
    
    }
    inline int div2() {
        int ans[103] = {0};
        int i, res = 0;
        for(i = 0; i < len; ++i) {
            ans[i] = (pow[i]+res*10)/2;
            res = (pow[i]+res*10)%2;
        }
        if(ans[0] == 0) len--;
        for(i = 0+(ans[0] == 0); i < len+(ans[0] == 0); i++)
            pow[i-(ans[0] == 0)] = ans[i];
        return res;
    }
    Mat operator ^ (Mat a, int pow[]) {
        Mat c;
        for (int i = 0; i <  (1 << m); i++)
            for (int j = 0; j <  (1 << m); j++)
                c.mat[i][j] = (i == j);
        while (len) {
            if (div2() )
                         c = c * a;
            a = a * a;
        }
        return c;
    }
    string s;
    int main() {
        ios::sync_with_stdio (0);
        while(cin >> s >> m >> mod){
        for (int i = 0; i < s.size(); ++i)
            pow[i] = s[i] - '0';
        len = s.size();
        for (int i = len - 1; i >= 0; i--) {
            if (pow[i]) {
                --pow[i];
                break;
            }
            else
                pow[i] = 9;
        }
        if (pow[0] == 0) {
            for (int i = 0; i < len - 1; i++) pow[i] = 9;
            pow[--len]=0;
        }
        for (int i = 0; i < (1 << m); i++)
            for (int j = 0; j < (1 << m); j++) {
                mx.mat[i][j] = 1;
                for (int k = 0, tem = i ^ j; k < m - 1; k++)
                    if (  (tem & 1 << k) == 0  && (tem & 1 << k + 1) == 0
    &&( ( (i & 1 << k) > 0 && (i & 1 << k + 1) > 0) || ( ( (i & 1 << k) == 0 && (i & 1 << k + 1) == 0) ) ) ) {
                        mx.mat[i][j] = 0;
                        break;
                    }
            }
        mx = mx ^ pow;
        int ans = 0;
        for (int i = 0; i < (1 << m); i++)
            for (int j = 0; j < (1 << m); j++) {
                ans += mx.mat[i][j];
                while (ans >= mod) ans -= mod;
            }
        cout << ans << endl;
        }
    }
    View Code

                 

  • 相关阅读:
    Webpack 学习2
    Webpack 学习
    JS魔法堂:彻底理解0.1 + 0.2 === 0.30000000000000004的背后
    JS魔法堂:再识Number type
    基础野:细说浮点数
    基础野:细说有符号整数
    基础野:细说无符号整数
    基础野:细说原码、反码和补码
    Vim魔法堂:认识快捷键绑定
    Httpd运维日志:通过apxs添加模块
  • 原文地址:https://www.cnblogs.com/keam37/p/4012789.html
Copyright © 2011-2022 走看看