题目

题目描述

牛式的定义,我们首先需要看下面这个算式结构:

  1. * * *
  2. x * *
  3. -------
  4. * * * <-- partial product 1
  5. * * * <-- partial product 2
  6. -------
  7. * * * *

这是一个乘法结构,我们给出一个数字集合,例如{2,3,5,7},如果我们能够集合里面的数字代替所有的*,使得这个乘法成立的话,那么这就是一个牛式。对于给出的集合,我们需要找出总共有多少个牛式。

数据范围

集合中的数字只能是从{1,2,3,4,5,6,7,8,9}中挑选。

样例输入

第一行输入所给集合中元素个数,下一行写出集合中的元素

5

2 3 4 6 8

样例输出

1

解题思路

因为数据量不大,所以我直接用枚举的方式,产生每一个被乘数与乘数,然后判断是否它的所有位都是由集合中的元素组合的。枚举出所有的情况,然后统计符合条件的。

Tip: 我在编码实现的时候遇到一个问题,我在本地测试样例发现可以通过,输出是1,但是当我提交到USACO的判题系统上时,它给我的反馈是我的第一组样例输出为21,我总共提交了十几次,始终不知道是什么原因造成的。后来看了下官方的文档,发现有可能是数组越界...后来思考了很久,终于让我找到了代码的bug!总之,以后编码的时候一定要细心,这种小错误真的很浪费时间,如果真的在比赛中出现这种情况很有可能你就因此与奖牌失之交臂。

解题代码

  1. /*
  2. ID: yinzong2
  3. PROG: crypt1
  4. LANG: C++11
  5. */
  6. #define MARK
  7. #include<cstdio>
  8. #include<set>
  9. #include<cstdlib>
  10. #include<algorithm>
  11. using namespace std;
  12. set<int> numSet;
  13. int n, cnt;
  14. int num[10];
  15. bool test(int x, int length) {
  16. int a[10];//就是这个数组,最开始的时候我开小了,但是在本地样例可以过。
  17. int len = 0;
  18. while(x) {
  19. a[len++] = x%10;
  20. x /= 10;
  21. }
  22. if(len != length) return false;
  23. for(int i = 0; i < len; i++) {
  24. if(numSet.find(a[i]) == numSet.end()) {
  25. return false;
  26. }
  27. }
  28. return true;
  29. }
  30. //产生乘数
  31. void makeMultiplier(int multiplier, int cur, int multiplicand) {
  32. if(cur >= 2) {
  33. int firstMul = (multiplier%10) * multiplicand;
  34. if(test(firstMul, 3)) {//判断是否符条件,应该是一个3位数
  35. int secondMul = (multiplier/10) * multiplicand;
  36. if(test(secondMul, 3)) {//同上
  37. int sum = secondMul*10 + firstMul;
  38. if(test(sum, 4)) {//同上,最后的和是4位的
  39. cnt++;
  40. }
  41. }
  42. }
  43. return ;
  44. }
  45. for(int i = 0; i < n; i++) {
  46. multiplier += num[i];
  47. if(0 == cur) {
  48. multiplier *= 10;
  49. }
  50. makeMultiplier(multiplier, cur+1, multiplicand);
  51. //状态还原
  52. if(0 == cur) {
  53. multiplier /= 10;
  54. }
  55. multiplier -= num[i];
  56. }
  57. }
  58. //产生被乘数
  59. void makeMultiplicand(int multiplicand, int cur) {
  60. if(cur >= 3) {
  61. makeMultiplier(0, 0, multiplicand);
  62. return ;
  63. }
  64. for(int i = 0; i < n; i++) {
  65. multiplicand += num[i];
  66. if(cur < 2) {
  67. multiplicand *= 10;
  68. }
  69. makeMultiplicand(multiplicand, cur+1);
  70. //状态还原
  71. if(cur < 2) {
  72. multiplicand /= 10;
  73. }
  74. multiplicand -= num[i];
  75. }
  76. }
  77. int main() {
  78. #ifdef MARK
  79. freopen("crypt1.in", "r", stdin);
  80. freopen("crypt1.out", "w", stdout);
  81. #endif // MARK
  82. while(~scanf("%d", &n)) {
  83. numSet.clear();
  84. for(int i = 0; i < n; i++) {
  85. scanf("%d", &num[i]);
  86. numSet.insert(num[i]);
  87. }
  88. cnt = 0;
  89. makeMultiplicand(0, 0);
  90. printf("%d\n", cnt);
  91. }
  92. return 0;
  93. }

(2017.08.20增加该部分)上面这种写法其实不是很直接,很容易出错。我今天又重新写了一遍,我觉得代码应该以最符合直觉的状态呈现出来,这样就容易读,也容易写。虽然可能会稍微长一点,但是不会出错,基本一遍就能过。

  1. /*
  2. ID: yinzong2
  3. PROG: crypt1
  4. LANG: C++11
  5. */
  6. #define MARK
  7. #include <iostream>
  8. #include <cstring>
  9. using namespace std;
  10. int n, cnt;
  11. int collect[10], num1[5], num2[5], prod1[5], prod2[5], sum[5];
  12. bool judge() {
  13. for (int i = 0; i < 3; ++i) {
  14. prod1[i] = num2[0]*num1[i];
  15. prod2[i] = num2[1]*num1[i];
  16. }
  17. prod1[3] = prod2[3] = 0;
  18. for (int i = 0; i < 3; ++i) {
  19. prod1[i+1] += (prod1[i]/10);
  20. prod1[i] = (prod1[i]%10);
  21. prod2[i+1] += (prod2[i]/10);
  22. prod2[i] = (prod2[i]%10);
  23. }
  24. if (prod1[3] != 0 || prod2[3] != 0) {
  25. return false;
  26. }
  27. sum[0] = prod1[0];
  28. for (int i = 1; i < 3; ++i) {
  29. sum[i] = prod1[i] + prod2[i-1];
  30. }
  31. sum[3] = prod2[2];
  32. sum[4] = 0;
  33. for (int i = 0; i < 4; ++i) {
  34. sum[i+1] += (sum[i]/10);
  35. sum[i] = sum[i]%10;
  36. }
  37. if (sum[4] != 0) {
  38. return false;
  39. }
  40. for (int i = 0; i < 3; ++i) {
  41. bool flag = false;
  42. for (int j = 0; j < n; ++j) {
  43. if (prod1[i] == collect[j]) {
  44. flag = true;
  45. break;
  46. }
  47. }
  48. if (!flag) {
  49. return false;
  50. }
  51. }
  52. for (int i = 0; i < 3; ++i) {
  53. bool flag = false;
  54. for (int j = 0; j < n; ++j) {
  55. if (prod2[i] == collect[j]) {
  56. flag = true;
  57. break;
  58. }
  59. }
  60. if (!flag) {
  61. return false;
  62. }
  63. }
  64. for (int i = 0; i < 4; ++i) {
  65. bool flag = false;
  66. for (int j = 0; j < n; ++j) {
  67. if (sum[i] == collect[j]) {
  68. flag = true;
  69. break;
  70. }
  71. }
  72. if (!flag) {
  73. return false;
  74. }
  75. }
  76. return true;
  77. }
  78. void produce2(int cur) {
  79. if (cur == 2) {
  80. if (judge()) {
  81. cnt++;
  82. }
  83. return ;
  84. }
  85. for (int i = 0; i < n; ++i) {
  86. num2[cur] = collect[i];
  87. produce2(cur+1);
  88. }
  89. }
  90. void produce(int cur) {
  91. if (cur == 3) {
  92. produce2(0);
  93. return ;
  94. }
  95. for (int i = 0; i < n; ++i) {
  96. num1[cur] = collect[i];
  97. produce(cur+1);
  98. }
  99. }
  100. int main() {
  101. #ifdef MARK
  102. freopen("crypt1.in", "r", stdin);
  103. freopen("crypt1.out", "w", stdout);
  104. #endif // MARK
  105. while (cin>>n) {
  106. for (int i = 0; i < n; ++i) {
  107. cin >> collect[i];
  108. }
  109. cnt = 0;
  110. produce(0);
  111. cout << cnt << endl;
  112. }
  113. return 0;
  114. }

解题思路(Type 2)

思路其实与上述保持一致,但是由于代码不简洁,在参考了大牛的代码之后,我准备重构一下代码。我们在枚举和判断的时候都可以写的更加优美,大牛毕竟是大牛。

解题代码(Type 2)

  1. /*
  2. ID: yinzong2
  3. PROG: crypt1
  4. LANG: C++11
  5. */
  6. #define MARK
  7. #include<cstdio>
  8. #include<cstring>
  9. #include<cstdlib>
  10. using namespace std;
  11. int n;
  12. int numSet[10];
  13. bool vis[10];
  14. bool ok(int x) {
  15. while(x) {
  16. if(!vis[x%10]) return false;
  17. x /= 10;
  18. }
  19. return true;
  20. }
  21. bool test(int a, int b, int c, int d, int e) {
  22. int first = a*100 + b*10 + c;
  23. int mul1 = e * first;
  24. int mul2 = d * first;
  25. int sum = mul2 * 10 + mul1;
  26. if(mul1 < 100 || mul1 > 999) return false;
  27. if(mul2 < 100 || mul2 > 999) return false;
  28. if(sum < 1000 || sum > 9999) return false;
  29. return ok(mul1) && ok(mul2) && ok(sum);
  30. }
  31. int main() {
  32. #ifdef MARK
  33. freopen("crypt1.in", "r", stdin);
  34. freopen("crypt1.out", "w", stdout);
  35. #endif // MARK
  36. while(~scanf("%d", &n)) {
  37. memset(vis, false, sizeof(vis));
  38. for(int i = 0; i < n; i++) {
  39. scanf("%d", &numSet[i]);
  40. vis[numSet[i]] = true;
  41. }
  42. int a,b,c,d,e;
  43. int cnt = 0;
  44. for(int i = 0; i < n; i++) {
  45. a = numSet[i];
  46. for(int j = 0; j < n; j++) {
  47. b = numSet[j];
  48. for(int k = 0; k < n; k++) {
  49. c = numSet[k];
  50. for(int p = 0; p < n; p++) {
  51. d = numSet[p];
  52. if((a*d) >= 10) continue;//会产生一个四位数,剪枝
  53. for(int q = 0; q < n; q++) {
  54. e = numSet[q];
  55. if((a*e) >= 10) continue;//会产生一个四位数,剪枝
  56. if(test(a,b,c,d,e)) {
  57. cnt++;
  58. }
  59. }
  60. }
  61. }
  62. }
  63. }
  64. printf("%d\n", cnt);
  65. }
  66. return 0;
  67. }

USACO Section 1.3 Prime Cryptarithm 解题报告的更多相关文章

  1. USACO Section 1.5 Prime Palindromes 解题报告

    题目 题目描述 题目就是给定一个区间[a,b]((5 <= a < b <= 100,000,000)),我们需要找到这个区间内所有既是回文串又是素数的数字. 输入样例 5 500 ...

  2. USACO Section1.3 Prime Cryptarithm 解题报告

    crypt1解题报告 —— icedream61 博客园(转载请注明出处)--------------------------------------------------------------- ...

  3. USACO Section 1.4 Arithmetic Progressions 解题报告

    题目 题目描述 现在给你一个数集,里面的数字都是由p^2+q^2这种形式构成的0 <= p,q <= M,我现在需要你在其中找出一个长为N的等差数列,数列中的第一个数字为a,公差为b,当你 ...

  4. USACO Section 1.3 Combination Lock 解题报告

    题目 题目描述 农夫John的牛从农场逃脱出去了,所以他决定用一个密码锁来把农场的门锁起来,这个密码锁有三个表盘,每个表盘都是环形的,而且上面刻有1~N,现在John设了一个开锁密码,而且这个锁的设计 ...

  5. USACO Section 1.3 Barn Repair 解题报告

    题目 题目描述 某农夫有一个养牛场,所有的牛圈都相邻的排成一排(共有S个牛圈),每个牛圈里面最多只圈养一头牛.有一天狂风卷积着乌云,电闪雷鸣,把牛圈的门给刮走了.幸运的是,有些牛因为放假,所以没在自己 ...

  6. USACO Section 1.3 Mixing Milk 解题报告

    题目 题目描述 Merry Milk Makers 公司的业务是销售牛奶.它从农夫那里收购N单位的牛奶,然后销售出去.现在有M个农夫,每个农夫都存有一定量的牛奶,而且每个农夫都会有自己的定价.假设所有 ...

  7. USACO Section 1.2 Dual Palindromes 解题报告

    题目 题目描述 有一些数(如 21),在十进制时不是回文数,但在其它进制(如二进制时为 10101)时就是回文数. 编一个程序,从文件读入两个十进制数N.S.然后找出前 N 个满足大于 S 且在两种以 ...

  8. USACO Section 1.2 Palindromic Squares 解题报告

    题目 题目描述 输入一个基数B,现在要从1到300之间找出一些符合要求的数字N.如果N的平方转换成B进制数之后是一个回文串,那么N就符合要求.我们将N转换成B进制数输出,然后再将N的平方转换成B进制数 ...

  9. USACO Section 1.2 Milking Cows 解题报告

    题目 题目描述 有3个农夫每天早上五点钟便起床去挤牛奶,现在第一个农夫挤牛奶的时刻为300(五点钟之后的第300个分钟开始),1000的时候结束.第二个农夫从700开始,1200结束.最后一个农夫从1 ...

随机推荐

  1. zencart 自定义函数

    ---------------------------------------------------------------------------------------------------- ...

  2. hdu_2111_Saving HDU(贪心)

    题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=2111 题意:给你n个物品的单位体积价值和体积,求装满容量v的背包的最大价值. 题解:乍一看还以为是背包 ...

  3. LeetCode OJ 141. Linked List Cycle

    Given a linked list, determine if it has a cycle in it. Follow up:Can you solve it without using ext ...

  4. 被非技术瓶颈阻挡了,没钱买Mac,挣扎ing

    最近一直没来写博客,因为一直在找刷盘子.服务生.看店的工. 已经找到,主要因为前阵子天不热,所以酒馆的顾客不多.现在好了. 只好买个Mac mini,看了很多帖子,也只好暂时折中这样了.Mac买不起. ...

  5. 用 gulp.spritesmith 自动化雪碧图

    一.安装nodejs之后,要设置两个环境变量 在 计算机右击属性---高级系统设置---高级---环境变量 打开窗口 新建2个环境变量,它们的值分别是nodejs根目录下的node_modules路径 ...

  6. Linux查看CPU和内存使用情况 【转】

    Linux查看CPU和内存使用情况 在系统维护的过程中,随时可能有需要查看 CPU 使用率,并根据相应信息分析系统状况的需要.在 CentOS 中,可以通过 top 命令来查看 CPU 使用状况.运行 ...

  7. perl-cgi基础

    来源: http://www.cnblogs.com/itech/archive/2012/09/22/2698553.html 代码: http://xxxxx/cgi/perl-cgi.cgi?n ...

  8. git 提交到github时不用每次都输入用户名,密码

    Permanently authenticating with Git repositories, Run following command to enable credential caching ...

  9. ng-init小解

    ng-init可有多个表达式 ng-init= "a= 1;b= 2" 在这里头定义的变量会加入scope作用域 ng-init只能加入不必要的简单逻辑,输入alert() 定义数 ...

  10. Windows任务管理器中内存使用、虚拟内存区别及与页面文件的关系

    原文地址:Windows任务管理器中内存使用.虚拟内存区别及与页面文件的关系 虚拟内存(VirtualMemory)是Windows管理所有可用内存的方式.对于32位Windows系统,每个进程所用到 ...