zoukankan      html  css  js  c++  java
  • 蓝桥杯省赛编程大题——骰子问题

    作为第二道编程大题,难度也没有想象中那么难。只怪我当时没有认真的静下心来仔细的理解题目意思。连样例都没有看懂,高数课闲来无事,便静下来认真想了一下。

    大致的题目意思是给你n个骰子,让你堆起来,并且告诉你有一些面是不能靠在一起的。问你总共有多少总方案数。(骰子规定1和4相对,2和5相对,3和6相对)

    输入n m 表示骰子的个数和不能靠在一起的个数。

    输入m行,每行两个数a b 表示a和b两面不能靠在一起。

    输出一行方案数,数据较大请模100000000+7;

    样例输入:

    2 1

    1 2

    样例输出:

    544

    60%的数据是n<100的

    100%的数据是n<10^9, m<36;

    对于60%的数据,dp的思路是很好想的。比赛的时候也已经想到了。但是因为没有想清楚样例,从而把题目想复杂了。写了一堆的map balabala~

    正确理解题目意思后,我们可以发现要继续在n-1颗骰子上添加一颗骰子,我们需要知道原来的第n-1颗骰子的顶面和当前骰子的底面。因为骰子的底面可以由顶面知道,所以dp数组需要用一维记录顶面就好。

    dp[i][j] : 放置好前 i 个骰子后并且顶面点数是j的翻案数。

    此时我们只要考虑第 i 个骰子和第 i-1 个骰子不会冲突就行。

    dp[i][j] += dp[i-1][k] *4; (状态k与状态j的两个骰子不会冲突,乘4的原因是骰子以j为顶面的方案有4种);

    dp[1][j] = 4; (初始化每个顶面向上都有4种方案);

    计算骰子的对面的点数。观察课发现,每个面的点数与对面的点数都相差3,即 对面的点数 = (当前面的点数 + 3) % 6; 当然点数3的时候要进行特判。

    由此,我们可以通过60%的数据。

    对于100%的数据,数量级一下增大到了10^9。确实挺吓人。但要知道数量级如此大的话复杂度一定不会是O(n),而前面我们可以看出来是一个递推式,那么,拿一个学长的话来说“傻子都知道是矩阵快速幂”。(弱弱说一句,比赛时我也想得到是矩阵快速幂可解,奈何题意没理解正确,dp没写出来,快速幂也就没想了。不然还指不定推不推的出来呢)。

    由前面的dp方程我们可以知道,答案的矩阵肯定是一个1*6的矩阵。那么要用矩阵快速幂,另一个矩阵怎么也得是6*6的吧?
    其实我们可以根据转移可知共有6*6种转移方式。而是否可以转移正好可以用6*6的矩阵表示。

    那么现在有一个答案矩阵

    A[] = {4,4,4,4,4,4}

    A[i] 表示以i点数为顶点的方案数

    还有一个转移矩阵初始为

    B[][] = {

    4,4,4,4,4,4,

    4,4,4,4,4,4,

    4,4,4,4,4,4,

    4,4,4,4,4,4,

    4,4,4,4,4,4,

    4,4,4,4,4,4

    }

    B矩阵的意思是B[i][j]元已i点数为顶点的骰子柱在放一个以j为顶点的骰子的方案数。这样和1*6的矩阵相乘的话得到的 _A[6] 矩阵 依旧表示各顶点的方案数。

    对于每组不可相靠在一起的情况,我们只需要在B数组的相应位置置为0就好

    于是要求解 |A*B^(n-1)| 就行。

      1 #include <cstring>
      2 #include <iostream>
      3 using namespace std;
      4 
      5 const long long MOD = 1000000000 + 7;
      6 
      7 int n, m;
      8 bool vis[7][7];
      9 
     10 int solve_01 () {
     11     long long dp[110][7];
     12 
     13     memset(dp, 0, sizeof(dp));
     14     for (int i=1; i<7; i++) {
     15         dp[1][i] = 4;
     16     }
     17 
     18     for (int i=2; i<=n; i++) {
     19         for (int j=1; j<=6; j++) {
     20             for (int k=1; k<=6; k++) {
     21 
     22                 int tmp = (j + 3) % 6;
     23                 if (tmp == 0) tmp = 6;
     24 
     25                 if (vis[k][tmp]) {
     26                     dp[i][j] = (dp[i][j] + dp[i-1][k] * 4) % MOD;
     27                 }
     28             }
     29         }
     30     }
     31 
     32     long long sum=0;
     33     for (int i=1; i<=6; i++) {
     34         sum = (sum + dp[n][i]) % MOD;
     35     }
     36     return sum % MOD;
     37 }
     38 
     39 
     40 struct Node {
     41     long long a[7][7];
     42 
     43     Node () {
     44         memset(a, 0, sizeof(a));
     45         for (int i=0; i<7; i++) {
     46             a[i][i] = 1;
     47         }
     48     }
     49 
     50     void show() {
     51         cout << "=====Node=====" << endl;
     52         for (int i=1; i<=6; i++) {
     53             for (int j=1; j<=6; j++) {
     54                 cout << a[i][j] << " ";
     55             }
     56             cout << endl;
     57         }
     58     }
     59 };
     60 
     61 Node mul (Node a,Node b){ 
     62     Node c;  
     63     for (int i=1; i<=6; i++){  
     64         for (int j=1; j<=6; j++){  
     65             c.a[i][j]=0;  
     66             for (int v=1; v<=6; v++){  
     67                 c.a[i][j] += (a.a[i][v] * b.a[v][j]) % MOD;  
     68             }  
     69             c.a[i][j]%=MOD;  
     70         }
     71     }
     72     return c;  
     73 }
     74 
     75 Node power(Node s, int n) {
     76     Node res;
     77     while (n > 0) {
     78         if (n&1) res = mul(res, s);
     79         s = mul(s, s);
     80         n>>=1;
     81     }
     82     return res;
     83 }
     84 
     85 int solve_02 () {
     86 
     87     Node s;
     88     memset(s.a, 0, sizeof(s));
     89     for (int i=1; i<=6; i++) {
     90         for (int j=1; j<=6; j++) {
     91             if (vis[i][j]) {
     92                 int tmp = (j + 3) % 6;
     93                 if (tmp == 0) tmp = 6;
     94                 s.a[i][tmp] = 4;
     95             }
     96         }
     97     }
     98     
     99     Node rec = power(s, n-1);
    100 
    101     long long ans = 0;
    102     for (int i=1; i<=6; i++) {
    103         for (int j=1; j<=6; j++) {
    104             ans = (ans + rec.a[i][j] * 4) % MOD;
    105         }
    106     }
    107     return ans%MOD;
    108 }
    109 
    110 int main () {
    111     memset(vis, true, sizeof(vis));
    112     
    113     cin >> n >> m;
    114 
    115     int a, b;
    116     for (int i=0; i<m; i++) {
    117         cin >> a >> b;
    118         vis[a][b] = false;
    119         vis[b][a] = false;
    120     }
    121 
    122     int res = solve_01();
    123 
    124     int rec = solve_02();
    125 
    126     cout << res << " " << rec << endl;
    127     return 0;
    128 }
    View Code

    最后,代码是自己赛后写的,思想是前面说的,solve_01是dp解法,solve_02是快速幂算法。可能还有bug,请多指教。

  • 相关阅读:
    Ne10编译安装
    AR中的SLAM(一)
    2016总结&2017计划
    DSO之光度标定
    DBoW2库介绍
    Kinect2.0 for Mac开箱
    SVO原理解析
    【漏洞复现】PHPCMS wap模块 SQL注入(附EXP)
    【编程开发】PHP---面向对象教程
    【编程开发】Python---列表
  • 原文地址:https://www.cnblogs.com/xuelanghu/p/4425891.html
Copyright © 2011-2022 走看看