博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
CCF201409-5 拼图(30分)
阅读量:5967 次
发布时间:2019-06-19

本文共 5934 字,大约阅读时间需要 19 分钟。

试题编号: 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。

问题链接:。

问题描述:(参见上文)

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

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

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

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

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

 

  

 

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

提交后得30分的程序如下:

/* CCF201409-5 拼图 */#include 
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<=m if(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 * 6 b1 = 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 / 6 b1 = 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; } else return 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分的程序如下:

/* CCF201409-5 拼图 */#include 
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<=m if(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 * 6 b1 = 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 / 6 b1 = 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; } else return 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 * 6        b1 = 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/7564110.html

你可能感兴趣的文章
Line: 220 - com/opensymphony/xwork2/spring/SpringObjectFactory.java:220:-1
查看>>
oracle 常用命令大汇总
查看>>
2012年春运火车票电话和网上订票技巧、攻略
查看>>
根据request获取请求路径
查看>>
mysql 并行复制
查看>>
傲不可长,欲不可纵,乐不可极,志不可满——提高个人修养
查看>>
linux系统增加swap容量的方法
查看>>
后台调用gps
查看>>
HTML5标签的语义认知和理解(1)
查看>>
MySQL日志功能详解(2)
查看>>
HP LaserJet 305X 和 339X 系列一体机如何设置手动或自动接收传真?
查看>>
linux之权限之隐藏权限
查看>>
XDCTF成长记录
查看>>
Linux系统中的文本处理工具
查看>>
IDE---Python IDE之Eric5在window下的安装
查看>>
Mybatis调用Oracle中的存储过程和function
查看>>
telnet :No route to host
查看>>
基本安装lnmp环境
查看>>
yum源资料汇总
查看>>
7、MTC与MTV,http请求介绍
查看>>