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;
    }
}

时间: 2024-08-26 20:26:55

SGU 197.Nice Patterns Strike Back的相关文章

SGU 197 Nice Patterns Strike Back || ZOJ 2317 Nice Patterns Strike Back

题目链接~~> 做题感悟:做了这题感觉学习了不少东西,首先是关于状态压缩推公式学会了. 解题思路: 构造矩阵: B[ i ][ j ] (i , j 为状态,0 <= i ,j  <= (1<<m) - 1 ) , 如果 B[ i ] [ j ]  等于 1 代表状态 i 与状态 j 相互兼容(i , j 可以在相邻两行),如果为 0 代表不可以相邻,还要有一个原始矩阵 A ,(1<<m)-1 行 ,1列的矩阵  ,代表第一行各种状态的方案数,这样 B *  A

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

【ZOJ】Nice Patterns Strike Back(矩阵快速乘法)

dp[[i][j] = sum(dp[i - 1][k]) (k -> j) 状态方程,因为N很大而M很小,所以第一时间可以想到矩阵优化 可能之前没做过类似的题被卡的很厉害. 另外用C++写大数真心麻烦.. #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn = 45; const int maxd = 30005; char n[ma

ZOJ 2317 Nice Patterns Strike Back

题意 在一个N*M的矩阵中给每个格子染上黑白色,要求任意一个2*2的矩阵颜色不能一样,N<=10^100,m<=5. 解法 首先看这个题,若n和m很小,则我们可以直接用状态压缩乱搞,但是N太大了,显然只能是快速幂(看到这个题的第一感觉),然后就是构造矩阵,在矩阵快速幂,不说了,网上说的比我好的太多了.这个题我并不想写这个博客的,但是由于它是我第一个java程序(虽然以前写过一个,不过那个是a+b问题),所以纪念一下 import java.util.*; import java.math.*;

zoj 2317 Nice Patterns Strike Back(矩阵乘法)

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1317 给出一个n*m的矩阵(n <= 10^100, m <= 5),对于2*2的子方格若全是黑色或全是白色的是非法的,用黑白两色去染n*m的方格,问共有多少种合法的染色方案. 构造出转移矩阵,上一行向下一行的转移矩阵,因为m<=5,每行最多有32个状态,可以进行状态压缩构造出一个32*32的转移矩阵A,A[i][j] = 1表示上一行i状态可以向下一行的j状态转移,

ASC1 E Nice Patterns Strike Back

题意:给你N×(1-5)的格子,每一个格子有两张颜色,其中2x2个格子内的颜色不能都相同. 解题思路:状态压缩+ 矩阵快速幂 +大数. 解题代码: 1 // File Name: e.cpp 2 // Author: darkdream 3 // Created Time: 2015年03月21日 星期六 19时58分58秒 4 5 #include<vector> 6 #include<list> 7 #include<map> 8 #include<set&g

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

传送门:点击打开链接 题意:告诉你矩阵大小是n*m,要求矩阵中不能有2*2的白色子矩阵或者黑色子矩阵,最后种类数模P 思路:如果不是大数,这道题还是非常有意思的..对于专门卡C++的题目也是醉了...因为n太大了,而m最大也只有5,很明显是大数上的快速矩阵幂. 问题是如何构造出矩阵出来,之前做过骨牌的题目,就是利用DFS来构造的,感觉这道题在思路上是一样的,同样也是利用DFS先构造出矩阵 然后直接大数+快速矩阵幂撸一发就行了 #include<map> #include<set>

sgu100~199题解

老东西了..发上来吧.. Sgu题解系列  南开中学邹事成 100:A+B略 101:Domino 给n块多米诺骨牌,每张骨牌两端各有从1到6的一个数字,现在要把这些骨牌排成一列,使相邻的两块骨牌相对的面所写的数字一样. 可以把每一块多米诺骨牌想象成一条边,把面上写的数字抽象成点,比如一块骨牌正面写的1反面写的2就想象成连了一条从1到2的边,那么这就是求一条有重边的欧拉回路了,dfs一下即可. 102:Coprimes给定n求从1到n中与n互质的数的个数. 可以把n质因数分解后直接代入欧拉函数.

ASC #1

开始套题训练,第一套ASC题目,记住不放过每一题,多独立思考. Problem A ZOJ 2313 Chinese Girls' Amusement 循环节 题意:给定n,为圆环长度,求k <= n/2,从1出发,每次顺时针方向走k步,即1->k+1->2*k+1,直到遇到一个已经走过的点结束,要求最终把所有点访问一遍,最后回到1,使得k尽量大. 代码: Problem B ZOJ 2314 Reactor Cooling 无源汇上下界网络流 题意:经典题,有上下界无源无汇的可行流,对