为了正常的体验网站,请在浏览器设置里面开启Javascript功能!
首页 > 垒骰子1

垒骰子1

2017-10-29 7页 doc 19KB 36阅读

用户头像

is_682974

暂无简介

举报
垒骰子1垒骰子1 大致的题目意思是给你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的思路是很好想的。比赛的时候也已经想到了。但...
垒骰子1
垒骰子1 大致的目意思是给你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 #include 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> a >> b; vis[a][b] = false; vis[b][a] = false; } int res = solve_01(); int rec = solve_02(); cout << res << " " << rec << endl; return 0; }
/
本文档为【垒骰子1】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。 本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。 网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。

历史搜索

    清空历史搜索