• 15年蓝桥杯第9题 矩阵快速幂


    题意and数据范围:
    赌圣atm晚年迷恋上了垒骰子,就是把骰子一个垒在另一个上边,不能歪歪扭扭,要垒成方柱体。
    经过长期观察,atm 发现了稳定骰子的奥秘:有些数字的面贴着会互相排斥!
    我们先来规范一下骰子:1 的对面是 4,2 的对面是 5,3 的对面是 6。
    假设有 m 组互斥现象,每组中的那两个数字的面紧贴在一起,骰子就不能稳定的垒起来。
    atm想计算一下有多少种不同的可能的垒骰子方式。
    两种垒骰子方式相同,当且仅当这两种方式中对应高度的骰子的对应数字的朝向都相同。
    由于方案数可能过多,请输出模 10^9 + 7 的结果。

    不要小看了 atm 的骰子数量哦~

    「输入格式」
    第一行两个整数 n m
    n表示骰子数目
    接下来 m 行,每行两个整数 a b ,表示 a 和 b 数字不能紧贴在一起。

    「输出格式」
    一行一个数,表示答案模 10^9 + 7 的结果。

    「样例输入」
    2 1
    1 2

    「样例输出」
    544
    「数据范围」
    对于 30% 的数据:n <= 5
    对于 60% 的数据:n <= 100
    对于 100% 的数据:0 < n <= 10^9, m <= 36


    资源约定:
    峰值内存消耗 < 256M
    CPU消耗 < 2ms

    第一个代码是dp,只是单纯的想用。超时超内存。

     1 /*
     2 思路:开始是一点思路都没有的,题都没明白,后来发现dp[]是可以做到的。因为要分类,应该是二维dp。dp[n][m] = sum(dp[n-1][x]) {m是指第n个方块朝上的数字
     3 ,x是指相对应的第n-1个方块,可以朝上的数字的状态和}。初始状态,dp[1][x] = 4; {1<=x<=6} 【当然这些思考过程是和大腿一起完成的、2333】
     4 当然我已经假设n是<10000的了。╭(╯^╰)╮
     5  */
     6 
     7 #include <stdio.h>
     8 #include <string.h>
     9 #include <iostream>
    10 #define maxn 10000
    11 #include <map>
    12 #define inf 1000000007
    13 using namespace std;
    14 
    15 long long int dp[maxn][10];
    16 int mp[maxn][maxn];
    17 map<int, int> mpp;
    18 
    19 int main() {
    20     int n, m, a, b;
    21     while(~scanf("%d%d", &n, &m)) {
    22         memset(mp, 0, sizeof(mp));
    23         memset(dp, 0, sizeof(dp));
    24         mpp.clear();
    25         mpp[1] = 4;
    26         mpp[2] = 5;
    27         mpp[3] = 6;
    28         mpp[4] = 1;
    29         mpp[5] = 2;
    30         mpp[6] = 3;
    31 
    32         for (int i=0; i<m; ++i) {
    33             scanf("%d%d", &a, &b);
    34             mp[a][b] = 1;
    35             mp[b][a] = 1;
    36         }
    37         for (int i=1; i<=6; ++i) { // 初始化
    38             dp[1][i] = 1; // 设为1 最后乘以4^n
    39         }
    40 
    41         for (int i=2; i<=n; ++i) {
    42             for (int j=1; j<=6; ++j) {
    43                 for (int k=1; k<=6; ++k) {
    44                     int bot = mpp[j];
    45                     if (mp[bot][k] == 0) {
    46                         dp[i][j] += dp[i-1][k];
    47                        // cout << "i=" << i <<  " " << "j==" << j << " " << "k==" << k << endl;
    48                     }
    49                 }
    50             }
    51         }
    52 
    53         long long ans = 0;
    54         for (int i=1; i<=6; ++i) {
    55             ans += dp[n][i];
    56         }
    57 
    58         for (int i=1; i<=n; ++i) {
    59             ans *= 4;
    60             ans %= inf;
    61         }
    62         printf("%lld
    ", ans);
    63     }
    64     return 0;
    65 }
    View Code

    第二个,矩阵快速幂right:

    太久不写矩阵快速幂了,从理解推公式到写完大概有三个多点了。T_T。最后发现bug是A1是单位矩阵!!!对啊!单位矩阵啊!只有A1[i][i] = 0的。然而我好像想成了所有的数都是1的了.......

      1 /*
      2  上一个dp的方法,因为n的范围,数组没法开那么大。讲道理,求4^n的时候。没有用快速幂也是一定会超时的。
      3  但是矩阵快速幂是perfect的、
      4  思路:首先我们考虑的依然是递推公式。对于一个六阶矩阵,An 第a行第b列的数字 代表第一层底层数字是a,第n层底层数字是b时的排放方式。
      5  然后A1 是一个单位矩阵。构造一个六阶矩阵X,第a行第b列代表相邻的两个格子底面是a 和 b时,能否成功连接。如果能,值设为1,否则设为0.
      6  【关于X矩阵还是不太懂的,推理的话就是矩阵乘法的知识,An的每个状态是怎么由An-1得到的。第n层底面数字是1的时候应该对应第n-1层底面数字是
      7  1~6的时候。是否稳定。所以X矩阵确实应该是这样的。】
      8 (如果把An矩阵改成只有第一行的b列是代表的第n层的底层数字的话。An = X * An-1。最后依然是An = X^(n-1)。)
      9  然后可以知道An = An-1 * X。A1是一个单位矩阵。所以呢。最后就是An = X^(n-1)。
     10  好了。问题就是代码实现了。T_T
     11  啊、、、对。注意。我们的An数组里存的是第n层的格子底层数字,所以判断是不是能和下一层稳定存在的时候要改回顶上的数字。
     12  这个就是在X矩阵的时候。
     13 */
     14 
     15 #include <stdio.h>
     16 #include <string.h>
     17 #include <iostream>
     18 #include <map>
     19 using namespace std;
     20 #define inf 1000000007
     21 
     22 struct Mat{
     23     long long m[10][10];
     24     Mat() {
     25         memset(m, 0, sizeof(m));
     26     }
     27 };
     28 
     29 long long Num_pow(long long a, int n) { // 求a*n快速幂
     30     long long ans = 1;
     31     while (n > 0) {
     32         if (n % 2 == 1) {
     33             ans *= a;
     34         }
     35         a *= a;
     36         n >>= 1;
     37     }
     38     return ans;
     39 }
     40 
     41 
     42 Mat Matrix_mul(Mat a, Mat b) { // 矩阵乘法
     43     Mat ans;
     44     for (int i=1; i<=6; ++i) {
     45         for (int j=1; j<=6; ++j) {
     46             for (int k=1; k<=6; ++k) {
     47                 ans.m[i][j] += a.m[i][k] * b.m[k][j];
     48                 ans.m[i][j] %= inf;
     49             }
     50         }
     51     }
     52     return ans;
     53 }
     54 
     55 Mat Matrix_pow(Mat a, int n) { //矩阵快速幂的实现
     56     Mat ans;
     57     for (int i=0; i<10; ++i) {
     58         ans.m[i][i] = 1;
     59     }
     60     while(n > 0) {
     61         if (n % 2 == 1) {
     62             ans = Matrix_mul(a, ans);
     63         }
     64         a= Matrix_mul(a, a);
     65         n >>= 1;
     66     }
     67     return ans;
     68 }
     69 
     70 
     71 int mp[10][10];
     72 map<int, int> mapp;
     73 
     74 int main() {
     75     int n, m;
     76     int a, b;
     77     while(~scanf("%d%d", &n, &m)) {
     78         mapp.clear();
     79         memset(mp, 0, sizeof(mp));
     80         for (int i=0; i<m; ++i) {
     81             scanf("%d%d", &a, &b);
     82             mp[a][b] = 1;
     83             mp[b][a] = 1;
     84         }
     85         mapp[1] = 4;
     86         mapp[2] = 5;
     87         mapp[3] = 6;
     88         mapp[4] = 1;
     89         mapp[5] = 2;
     90         mapp[6] = 3;
     91 
     92         Mat ans;
     93         Mat x;
     94         for (int i=1; i<=6; ++i) {
     95             for (int j=1; j<=6; ++j) {
     96                 int temp = mapp[j];
     97                 if (mp[i][temp] == 0)
     98                 x.m[i][j] = 1; // 能稳定连接
     99                 else x.m[i][j] = 0;
    100             }
    101         }
    102 
    103         ans = Matrix_pow(x, n-1);
    104         long long num = Num_pow(4, n);
    105         long long ans_num = 0;
    106         for (int i=1; i<=6; ++i) {
    107             for (int j=1; j<=6; ++j) {
    108                 ans_num += ans.m[i][j];
    109                 ans_num %= inf;
    110             }
    111         }
    112         num %= inf;
    113         ans_num *= num;
    114         ans_num %= inf;
    115         printf("%lld
    ", ans_num);
    116     }
    117     return 0;
    118 }
    View Code
  • 相关阅读:
    java图书管理系统界面版本+mysql数据库
    java数组实现的超市管理系统(控制台)
    Action<T>和Func<T>委托事例
    简单的委托示例
    使用静态方法CreateInstance()创建数组
    Span复习
    与预定义类型的用户类型强制转换
    实现自定义的索引运算符
    比较运算符的重载
    算术运算符的重载
  • 原文地址:https://www.cnblogs.com/icode-girl/p/5240250.html
Copyright © 2020-2023  润新知