zoukankan      html  css  js  c++  java
  • HDU 5434 Peace small elephant 状压dp+矩阵快速幂

    题目链接:

    http://acm.hdu.edu.cn/showproblem.php?pid=5434

    Peace small elephant

     
     Accepts: 38
     
     Submissions: 108
     Time Limit: 10000/5000 MS (Java/Others)
     
     Memory Limit: 65536/65536 K (Java/Others)
    问题描述
    小明很喜欢国际象棋,尤其喜欢国际象棋里面的大象(只要无阻挡能够斜着走任意格),但是他觉得国际象棋里的大象太凶残了,于是他想到了小象,
    小象就没有大象那么凶残,它的攻击范围是它当前格子直角所斜对的格子。现在小明要在棋盘上放很多个小象,有趣的是,当两个小象所在格子有公共边时,
    它们将合体变成合体象,多个小象满足条件也会合体,合体象的攻击范围也是它所覆盖格子区域直角所斜对的格子,现在要求任何一个象的攻击范围上是空的(即不摆放棋子),
    小明的棋盘很特殊,有m*nmn个格子,求满足条件的摆放的方案数,由于方案数太大,需要对10000000071000000007取模。
    下面给出几种形状下的象的攻击范围图,叉号表示攻击范围。
    
    
    输入描述
    输入有多组数据(最多55组),每组数据有两个整数n,mn,m含义如题目描述。
    1 leq m leq 7,1 leq n leq 10000000001m7,1n1000000000
    
    输出描述
    每组数据对应输出一行包含一个整数,表示满足条件的摆放的方案数。
    
    输入样例
    1 1
    2 3
    
    输出样例
    2
    50

    题解:

      状压dp+矩阵快速幂。

      由于m很小,我们考虑将每一列m行的状态压缩成一行,这一行对应的状态总数就是2^m种(m=7时,即:0000000~1111111)。

      接下来我们求一个矩阵mat[i][j],代表状态i和状态j是否冲突(比如说0000000和1111111不冲突,而1000000和0100000则冲突)。

    如果坐标(i,j),(i+1,j+1)存在小象,那么必须保证(i+1,j),(i,j+1)两个位置至少有一个棋子,按照这个规则,就能提前得到状态转移矩阵mat了。

      然后我们要一列一列的往棋盘上放棋子了(注意这时候棋盘已经状压成1*n了,是线性结构,而不是二维结构),由于我们已经得到转移矩阵mat[1<<m][1<<m]了,初始向量vec[1<<m]为全1(因为第一列所有的(1<<m)种状态都不会发生冲突,所以为全1)。我们的任务就是要求:

      mat^(n-1)*vec (mat^(n-1)表示做n-1次的矩阵乘)

      由于n非常大,所以我们需要用矩阵快速幂来求mat^(n-1);

      总的时间复杂度为 o( (2^m)*(2^m)*(2^m)*(logn) )=o(3e6)

    代码:

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 using namespace std;
     5 
     6 const int maxn = 155;
     7 const int mod = 1000000007;
     8 
     9 typedef long long LL;
    10 
    11 struct Matrix {
    12     int n, m;
    13     int val[maxn][maxn];
    14     Matrix(int n,int m) :n(n),m(m) {}
    15     Matrix() {}
    16     void init(int n, int m) { this->n = n; this->m = m; }
    17     //把向量看作是n*1的矩阵,所以不用考虑矩阵*向量的情况了。 
    18     friend Matrix operator * (const Matrix& mat1, const Matrix& mat2) {
    19         Matrix ret(mat1.n, mat2.m);
    20         for (int i = 0; i < ret.n; i++) {
    21             for (int j = 0; j < ret.m; j++) {
    22                 ret.val[i][j] = 0;
    23                 for (int k = 0; k < mat1.m; k++) {
    24                     ret.val[i][j] += (LL)mat1.val[i][k] * mat2.val[k][j]%mod;
    25                     ret.val[i][j] %= mod;
    26                 }
    27             }
    28         }
    29         return ret;
    30     }
    31 };
    32 
    33 //矩阵快速幂 
    34 void power(Matrix& mat, int n, Matrix& ans) {
    35     while (n > 0) {
    36         if (n % 2) ans = mat*ans;
    37         mat = mat*mat;
    38         n /= 2;
    39     }
    40 }
    41 
    42 int _n, m;
    43 
    44 //判断状态s1和状态s2是否冲突。 
    45 bool isOk(int s1, int s2) {
    46     for (int i = 0; i<m; i++) {
    47         if ((s1&(1 << i)) && !(s2&(1 << i))) {
    48             int j;
    49             j = i - 1;
    50             if (j >= 0) {
    51                 if ((s2&(1 << j)) && !(s1&(1 << j))) return false;
    52             }
    53             j = i + 1;
    54             if (j<m) {
    55                 if ((s2&(1 << j)) && !(s1&(1 << j))) return false;
    56             }
    57         }
    58     }
    59     return true;
    60 }
    61 
    62 Matrix mat, ans;
    63 
    64 void init() {
    65     mat.init(1 << m, 1 << m);
    66     for (int i = 0; i<mat.n; i++) {
    67         for (int j = 0; j<mat.m; j++) {
    68             if (isOk(i, j)) mat.val[i][j] = 1;
    69             else mat.val[i][j] = 0;
    70         }
    71     }
    72     ans.init(1 << m, 1);
    73     for (int i = 0; i < ans.n; i++) ans.val[i][0] = 1;
    74 }
    75 
    76 int main() {
    77     while (scanf("%d%d", &_n, &m) == 2 && _n) {
    78         init();
    79         power(mat, _n - 1, ans);
    80         int res = 0;
    81         for (int i = 0; i < ans.n; i++) {
    82             res += ans.val[i][0];
    83             res %= mod;
    84         }
    85         printf("%d
    ", res);
    86     }
    87     return 0;
    88 }
    View Code
  • 相关阅读:
    五步搞定Android开发环境部署!
    WebBrowser JS回调delphi的方法 (简单通用)
    Delphi根据方法名调用方法
    Delphi TstringList Stringlist的特殊用法
    delphi 获取webbrowser的cookies给Idhttp用
    HttpHelper类登录淘宝联盟并下载淘宝客订单xls
    我的常用笔记(GetAndroid,ADBDemo,GetSJ,GetTB)
    P1025 数的划分
    P1969 积木大赛
    P2038 无线网络发射器选址
  • 原文地址:https://www.cnblogs.com/fenice/p/5281921.html
Copyright © 2011-2022 走看看