蓝桥杯省赛编程大题——骰子问题
来源:互联网 发布:cab格式软件 编辑:程序博客网 时间:2024/06/05 05:26
作为第二道编程大题,难度也没有想象中那么难。只怪我当时没有认真的静下心来仔细的理解题目意思。连样例都没有看懂,高数课闲来无事,便静下来认真想了一下。
大致的题目意思是给你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)| 就行。
#include <cstring>#include <iostream>using namespace std;const long long MOD = 1000000000 + 7;int n, m;bool vis[7][7];int solve_01 () {long long dp[110][7];memset(dp, 0, sizeof(dp));for (int i=1; i<7; i++) {dp[1][i] = 4;}for (int i=2; i<=n; i++) {for (int j=1; j<=6; j++) {for (int k=1; k<=6; k++) {int tmp = (j + 3) % 6;if (tmp == 0) tmp = 6;if (vis[k][tmp]) {dp[i][j] = (dp[i][j] + dp[i-1][k] * 4) % MOD;}}}}long long sum=0;for (int i=1; i<=6; i++) {sum = (sum + dp[n][i]) % MOD;}return sum % MOD;}struct Node {long long a[7][7];Node () {memset(a, 0, sizeof(a));for (int i=0; i<7; i++) {a[i][i] = 1;}}void show() {cout << "=====Node=====" << endl;for (int i=1; i<=6; i++) {for (int j=1; j<=6; j++) {cout << a[i][j] << " ";}cout << endl;}}};Node mul (Node a,Node b){ Node c; for (int i=1; i<=6; i++){ for (int j=1; j<=6; j++){ c.a[i][j]=0; for (int v=1; v<=6; v++){ c.a[i][j] += (a.a[i][v] * b.a[v][j]) % MOD; } c.a[i][j]%=MOD; }}return c; }Node power(Node s, int n) {Node res;while (n > 0) {if (n&1) res = mul(res, s);s = mul(s, s);n>>=1;}return res;}int solve_02 () {Node s;memset(s.a, 0, sizeof(s));for (int i=1; i<=6; i++) {for (int j=1; j<=6; j++) {if (vis[i][j]) {int tmp = (j + 3) % 6;if (tmp == 0) tmp = 6;s.a[i][tmp] = 4;}}}Node rec = power(s, n-1);long long ans = 0;for (int i=1; i<=6; i++) {for (int j=1; j<=6; j++) {ans = (ans + rec.a[i][j] * 4) % MOD;}}return ans%MOD;}int main () {memset(vis, true, sizeof(vis));cin >> n >> m;int a, b;for (int i=0; i<m; i++) {cin >> a >> b;vis[a][b] = false;vis[b][a] = false;}int res = solve_01();int rec = solve_02();cout << res << " " << rec << endl;return 0;}
- 蓝桥杯省赛编程大题——骰子问题
- [编程题]骰子翻转
- 2015年第六届蓝桥杯C/C++程序设计本科B组省赛 垒骰子(编程大题)
- 2015年第六届蓝桥杯C/C++程序设计本科B组省赛 垒骰子(编程大题)
- 垒骰子—题解
- 掷骰子——柱状图
- 2015蓝桥杯省赛——叠骰子(第9题,DP)
- 2015蓝桥杯省赛——叠骰子(第9题,矩阵快速幂)
- 掷骰子问题
- 骰子游戏问题
- 阿里 骰子概率问题
- 骰子求和问题
- 骰子点数问题
- 掷骰子问题
- Introduction to Java Programming编程题5.29<掷骰子游戏>
- 简单C++程序——掷骰子
- 华为机试—掷骰子游戏
- 笔试题8. n个骰子的问题
- UESTC 852 -- 方老师与迷宫 (bfs)
- The 15th Zhejiang University Programming Contest
- 拷贝global memory,cudaMemcpyToSymbol 和cudaMemcpy函数是否有区别
- Android Bitmap在不加载图片的前提获取宽高
- 第六周 项目四-成员函数、友元函数和一般函数有区别
- 蓝桥杯省赛编程大题——骰子问题
- 腾讯2015实习面试
- js 打印 HTML 隐藏不想打印的元素
- ORACLE RAC数据库的启动与关闭
- 用DPM(Deformable Part Model,voc-release3.1)算法在INRIA数据集上训练自己的人体检测模型
- 《一个都不能死》 游戏开发 (物理引擎)
- C++定义的创建异常类
- 将xls转成protobuf供Unity使用的流程
- 在windows下运行Felzenszwalb的Deformable Part Model(DPM)源码voc-release3.1来训练自己的模型