试题编号: 201409-5
试题名称: 拼图
时间限制: 3.0s
内存限制: 256.0MB
问题描述:
问题描述
给出一个n×m的方格图,现在要用如下L型的积木拼到这个图中,使得方格图正好被拼满,请问总共有多少种拼法。其中,方格图的每一个方格正好能放积木中的一块。积木可以任意旋转。
输入格式
输入的第一行包含两个整数n, m,表示方格图的大小。
输出格式
输出一行,表示可以放的方案数,由于方案数可能很多,所以请输出方案数除以1,000,000,007的余数。
样例输入
6 2
样例输出
4
样例说明
四种拼法如下图所示:
评测用例规模与约定
在评测时将使用10个评测用例对你的程序进行评测。
  评测用例1和2满足:1<=n<=30,m=2。
  评测用例3和4满足:1<=n, m<=6。
  评测用例5满足:1<=n<=100,1<=m<=6。
  评测用例6和7满足:1<=n<=1000,1<=m<=6。
  评测用例8、9和10满足:1<=n<=10^15,1<=m<=7。

问题链接:CCF201409试题。

问题描述:(参见上文)。

问题分析:也许从数学上先推演一下比较好,这有点难。

看似可以用递归函数来实现,实际做起来没有那么容易。只得了30分,有胜于无而已。

对于输入的n和m,若n*m不是3的倍数,则肯定无法完全覆盖。同时,如果不是6的倍数则不能完全覆盖。

n和m哪个更大是不知道的,假设n<=m的情况下进行计算即可,若n>m将n和m交换即可。题意中则相反,是m<=n,实际上是一样的。

以下给出若各种拼图组合,可以在其基础上找出递归函数关系:

 

  

 

程序说明:程序有待改进,或者需要新的思路。

提交后得30分的C++语言程序如下:

/* CCF201409-5 拼图 */#include <iostream>using namespace std;const long long MOD = 1000000007;// 模幂计算函数
inline long long powermod(int x, int y, long long mod)
{long long ans = 1;while(y) {if(y & 1) {ans *= x;ans %= mod;}x *= x;x %= mod;y >>= 1;}return ans;
}long long puzzle(int n, int m)
{long long b1, b2;if(n <= 1 || m <= 1)return 0;// 面积不是3的倍数则不可能if((n * m) % 3 != 0)return 0;// 让n<=mif(n > m) {int temp = n;n = m;m = temp;}if(n == 2) {   // 2 * 3 * k, k = m / 3// n=2时,m必须是3的倍数if(m % 3 != 0)return 0;return powermod(2, m / 3, MOD);} else if(n == 3) { // 3 * 2 * k, k = m / 2// n=3时,m必须是2的倍数if(m % 2 != 0)return 0;return powermod(2, m / 2, MOD);} else if(n == 4 && m == 6) { // 4 * 6b1 = puzzle(2, m);  // 分为两半b2 = puzzle(2, 3);   // 4*6异形数量return (b1 * b1 + b2) % MOD;} else if(n == 4) { // 4 * 3 * 2 * k, k = m / 6 或 4 * 3 * 2 * k + 4 * 3, k = m / 6b1 = powermod(puzzle(4, 6), m / 6, MOD);if(m % 6 == 0) {return b1;} else if(m % 6 == 3) {// 除了组合,还需要考虑排列b2 = puzzle(3, 4);return b1 * b2 * (m / 6 + 1) % MOD;} elsereturn 0;} else if(n == 5 && m == 6) {long long b1, b2;b1 = puzzle(3, m);b2 = puzzle(2, m);return b1 * b2 * 2 % MOD;   // 64} else if(n == 5) {if(m % 6 != 0)return 0;return powermod(puzzle(5, 6), m / 6, MOD);} else if(n == 6 && m == 6) {// 上下分,左右分,4*6异形与2*6拼接,6*6异形(2种)b1 = puzzle(3, m);  // 上下分,或左右分b2 = puzzle(2, 3);   // 4*6异形数量return (b1 * b2 * 2 + b2 * puzzle(2, 6) * 4 + 2) % MOD;} else if(n == 6) {// 6*6不正确,这个计算就没有意义了return 0;} else {// 其他情况:不考虑return 0;}
}int main()
{int n, m;long long ans;cin >> n >> m;ans = puzzle(n, m);cout << ans << endl;return 0;
}

改进:上述程序提交后只得30分,所以进行了进一步的分析与改进:

1.使得方格图正好被拼满,需要m*n是6的倍数,因为积木块面积为3。程序中35-37行代码改为:

    // 方格图被完全拼满,面积不是6的倍数则不可能if((n * m) % 6 != 0)return 0;

2.根据题意,m最大为7,即只需要考虑m=2,3,4,5,6,7的情况。这也是得100分的希望所在。

所以,程序中只需要考虑n=2,3,4,5,6,7的情况(程序中,与题意相比,n和m互换)。

3.程序中增加n=7的代码,需要考虑6*7和7*m的情况。对于6*7的方格图,可以由6*2和6*5的方格图组成,也可以由6*3和6*4的方格图组成。

改进后提交得30分的C++语言程序如下:

/* CCF201409-5 拼图 */#include <iostream>using namespace std;const long long MOD = 1000000007;// 模幂计算函数
inline long long powermod(int x, int y, long long mod)
{long long ans = 1;while(y) {if(y & 1) {ans *= x;ans %= mod;}x *= x;x %= mod;y >>= 1;}return ans;
}long long puzzle(int n, int m)
{long long b1, b2;if(n <= 1 || m <= 1)return 0;// 方格图被完全拼满,面积不是6的倍数则不可能if((n * m) % 6 != 0)return 0;// 让n<=mif(n > m) {int temp = n;n = m;m = temp;}if(n == 2) {   // 2 * 3 * k, k = m / 3// n=2时,m必须是3的倍数if(m % 3 != 0)return 0;return powermod(2, m / 3, MOD);} else if(n == 3) { // 3 * 2 * k, k = m / 2// n=3时,m必须是2的倍数if(m % 2 != 0)return 0;return powermod(2, m / 2, MOD);} else if(n == 4 && m == 6) { // 4 * 6b1 = puzzle(2, m);  // 分为两半b2 = puzzle(2, 3);   // 4*6异形数量return (b1 * b1 + b2) % MOD;} else if(n == 4) { // 4 * 3 * 2 * k, k = m / 6 或 4 * 3 * 2 * k + 4 * 3, k = m / 6b1 = powermod(puzzle(4, 6), m / 6, MOD);if(m % 6 == 0) {return b1;} else if(m % 6 == 3) {// 除了组合,还需要考虑排列b2 = puzzle(3, 4);return b1 * b2 * (m / 6 + 1) % MOD;} elsereturn 0;} else if(n == 5 && m == 6) {long long b1, b2;b1 = puzzle(3, m);b2 = puzzle(2, m);return b1 * b2 * 2 % MOD;   // 64} else if(n == 5) {if(m % 6 != 0)return 0;return powermod(puzzle(5, 6), m / 6, MOD);} else if(n == 6 && m == 6) {// 上下分,左右分,4*6异形与2*6拼接,6*6异形(2种)b1 = puzzle(3, m);  // 上下分,或左右分b2 = puzzle(2, 3);   // 4*6异形数量return (b1 * b2 * 2 + b2 * puzzle(2, 6) * 4 + 2) % MOD;} else if(n == 6 && m == 7) {b1 = puzzle(2, 6) * puzzle(5, 6);b2 = puzzle(3, 6) * puzzle(4, 6);return (b1 + b2) % MOD;} else if(n == 6) {// 6*6不正确,这个计算就没有意义了return 0;} else if(n == 7) {return powermod(puzzle(6, 7), m / 6, MOD);} else {// 其他情况:不考虑return 0;}
}int main()
{int n, m;long long ans;cin >> n >> m;ans = puzzle(n, m);cout << ans << endl;return 0;
}

经过改进的程序仍然的30分,增加的有关7*m的代码完全不得分。

由于6*7的方格图,可以由6*2和6*5的方格图组成,也可以由6*3和6*4的方格图组成,那应该是以下几种方格图的组合数计算有错误:

6*2

6*5

6*3

6*4

经过仔细考察和梳理,终于发现4*6至少漏算了一个情况,至少应该如下图所示:

上述程序的56-50行改为(异形数量*2):

    } else if(n == 4 && m == 6) { // 4 * 6b1 = puzzle(2, m);      // 分为两半b2 = puzzle(2, 3) * 2;   // 4*6异形数量return (b1 * b1 + b2) % MOD;

改进后提交只得20分,分数更少了,怀疑测试数据有BUG。

下一步只能考虑先改进6*6的情形了。

 

转载于:https://www.cnblogs.com/tigerisland/p/7564111.html

CCF201409-5 拼图(30分)相关推荐

  1. 3分和30分文章差距在哪里?

    好的分析和可视化,可以提供大量的信息,同时兼顾简洁优雅. 今天我们抛开实验设计.方法和工作量等因素,仅从文章最吸引人的图片来讨论3分和30分(顶级)文章差距在哪里? 以2017年8月25日发表在Sci ...

  2. 微生物组:3分和30分文章差距在哪里?

    好的分析和可视化,可以提供大量的信息,同时兼顾简洁优雅. 今天我们抛开实验设计.方法和工作量等因素,仅从文章最吸引人的图片来讨论3分和30分(顶级)文章差距在哪里? 以2017年8月25日发表在Sci ...

  3. PAT甲级1038 Recover the Smallest Number (30 分):[C++题解]贪心、排列成最小的数、字符串

    文章目录 题目分析 题目来源 题目分析 来源:acwing 分析: 贪心: 对于字符串a和b,如果 a+b < b+a (这里+代表字符串中的连接)代表字典序更小.举例 a = 321 , b ...

  4. PAT甲级1147 Heaps (30 分):[C++题解]堆、树的遍历、dfs、完全二叉树建树

    文章目录 题目分析 题目来源 题目分析 来源:acwing 分析:给定完全二叉树,判断是否是堆,需要区分大根堆,小根堆.后面是输出后序遍历. AC代码 #include<bits/stdc++. ...

  5. PAT甲级1076 Forwards on Weibo (30 分) :[C++题解]图论、bfs

    文章目录 题目分析 题目来源 题目分析 来源:acwing 分析: BFS如何搜前k层?统计前k层的点数. ac代码 #include<bits/stdc++.h> using names ...

  6. PAT甲级1072 Gas Station (30 分):[C++题解]dijkstra算法、最短路

    文章目录 题目分析 题目来源 题目分析 来源:acwing 分析: 所有的dist[ ]都≤Ds:最小的dist[ ]最大; dist[ ] 总和最大. 由于加油站是字符,为了简单起见,将m个加油站编 ...

  7. PAT甲级1151 LCA in a Binary Tree (30 分):[C++题解]LCA、最低公共祖先、哈希表映射

    文章目录 题目分析 题目链接 题目分析 来源:acwing 分析: 和下面这道题几乎是同一题:PAT甲级1143 Lowest Common Ancestor (30 分):[C++题解]LCA.最低 ...

  8. PAT甲级1155 Heap Paths (30 分):[C++题解]堆、堆的遍历、树的遍历、dfs输出路径、完全二叉树建树

    文章目录 题目分析 题目链接 题目分析 来源:acwing 分析: 堆首先是完全二叉树,所以先建完全二叉树,由于给定的是层序遍历的数据,所以直接用数组即可,注意数组下标从1开始,这样便满足结点u和左儿 ...

  9. PAT甲级1107 Social Clusters (30 分):[C++题解]并查集,爱好、人数

    文章目录 题目分析 题目链接 题目分析 来源:acwing 分析: 凭爱好,分人群.注意点:爱好可传递.什么意思?意思是A和B的有共同爱好1, B和C有共同爱好2,那么认为A和C也是同一群人. 按照爱 ...

最新文章

  1. OPPO海外官方调试ID
  2. DataRow判断列名是否存在
  3. arcsde安装步骤_ArcGIS 9.3 安装之 SDE的安装及使用
  4. UA MATH564 概率论VI 数理统计基础5 F分布
  5. halcon学习笔记——(1)单摄像机标定
  6. 科大讯飞智慧医疗再出重磅,“智医助理”机器人顺利通过临床执业医师综合笔试...
  7. win7下nsis打包exe安装程序教程
  8. 理解 TCP(五):可靠性交付的实现
  9. 教你如何一篇博客读懂设计模式之—--工厂模式
  10. ubuntu16.04下wifi上网速度很慢的解决方案
  11. android ffmpeg编译so,Android FFmpeg学习(一),将FFmpeg编译成so文件
  12. 微信抢红包python脚本不用手机_用Python实现微信自动化抢红包,再也不用担心抢不到红包了...
  13. TensorFlow 教程 --教程--2.3MNIST机器学习入门
  14. 集成学习—决策树(CART)
  15. 年回报60%!孙正义如何经营“沉迷AI”的愿景基金?
  16. mysql批量插入之提高插入效率
  17. CCNA学习指南-----1-3章笔记
  18. Windows的快捷方式打开方式被修改后恢复方法
  19. maven打包报错failed: Unable to find a single main class from the following candidates []
  20. JavaSrcipt学习(学习打卡Day7)

热门文章

  1. eclipse执行单元测试报CreateProcess error=87的解决方法
  2. 天鹅给癞蛤蟆的回信[转贴]
  3. 【转】ubuntu,你改变了我的人生
  4. concurrent: wai notify notifyAll
  5. MySQL分组查询—简单使用
  6. SpringSecurity集中式整合之加入jsp
  7. SpringBoot自动配置【源码分析】-初始加载自动配置类
  8. 使用Dockerfile构建SpringBoot应用镜像
  9. hystrix相关配置
  10. Elastic-Job中的DataFlowJob