题目:输入一序列的正实数和幂次(正整数)对,然后打印结果(具体的比这个精细)

这道题是关于大数计算的(大数求幂),从开始建立思路,到写代码、调式到最后被AC以及最终的优化,总共用了差不多一天的时间。开始AC时使用空间500K,时间37MS,最后一次AC空间400K,时间0MS,有很大提高。这主要归功于加大了每次的数据处理量,减少了重计算次数以及降低循环代码量。还有就是在使用了二分递归,避免了重复计算。不好的一点是代码量太大,并且使用了太多的变量。

不管怎么样,为这道题付出了很多想法,后来的一些大的优化主要来自对底层的深入理解,代码的整体实现粒度是很细的,阅读起来可能会有些困难,但很是值得推敲的,具体实现代码如下:

[cpp] view plain copy

 
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. void add(char *s1, char *s2);
  5. char *multi(char *s1, char *s2);
  6. char *result(char *s, int n);
  7. int main(void) {
  8. char ch[100];
  9. char *res;
  10. int  num, np;
  11. char tem, *temp1, *temp2;
  12. char *chp;
  13. while ( scanf("%s%d", ch, &num) != EOF ) {
  14. chp = ch + strspn(ch, "0");           // 去掉前导0
  15. temp1 = &ch[strlen(ch)-1];
  16. if ( (temp2 = strchr(ch, '.')) != NULL ) {  // 如果有小数点
  17. while ( *temp1 == '0' )  // 去掉小数末尾的0
  18. *temp1-- = 0;
  19. np  = strlen(temp2) - 1;
  20. np *= num;                  // 小数位的num倍是最终结果的小数位数
  21. memmove(temp2, temp2+1, strlen(temp2));  // 去掉小数点
  22. }
  23. else
  24. np = 0;             // 整数
  25. res   = result(chp, num);
  26. //        printf("res: %s\n", res);
  27. temp1 = res + strspn(res, "0");
  28. temp2 = &res[strlen(res) - np];     // 定位小数点
  29. if ( temp1 >= temp2 && np != 0 )   // 如果结果小于1
  30. printf("%c%s\n", '.', temp2);
  31. else if ( np == 0 )              // 如果是整数
  32. printf("%s\n", temp1 == temp2 ? 0 : temp1);
  33. else {
  34. tem   = *temp2;         // 将该放小数点位置的源字符保存
  35. *temp2++ = 0;           // 这里将源结果字符串断开,块式输出效率高
  36. printf("%s%c%c%s\n", temp1,
  37. '.', tem,
  38. *temp2 == 0 ? "" : temp2);
  39. }
  40. free(res);
  41. }
  42. return 0;
  43. }
  44. char *result(char *s, int n) {
  45. char *res, *ch1, *ch2;
  46. if ( n == 1 )
  47. return multi(s, "1");  // 返回统一类型的可被free掉的数据空间
  48. else if ( n == 2 )
  49. return multi(s, s);
  50. else if ( n > 2 ) {
  51. ch1 = result(s, n >> 1);  // 二分递归计算
  52. if ( n % 2 != 0 ) {
  53. ch2 = result(s, n - (n >> 1));
  54. res = multi(ch1, ch2);
  55. free(ch2);   // result函数返回值得释放掉
  56. }
  57. else   // 如果n是偶数,可避免重复计算
  58. res = multi(ch1, ch1);
  59. free(ch1);
  60. return res;
  61. }
  62. }
  63. char *multi(char *s1, char *s2) {
  64. int  i1, i2;
  65. char *ch1, *ch2, *cp1, *cp2, *cp3;
  66. char chp[18];
  67. int  i, j, num, dis;
  68. long long j1, j2, j3; // 加大每次计算量
  69. i1 = strlen(s1);
  70. i2 = strlen(s2);
  71. ch1 = (char *)malloc(i1 + i2 + 2);  // 1 bit '\0', 1 carry bit(reserved for)
  72. if ( strncmp(s2, "1", 1) == 0 && i2 == 1 ) {
  73. memcpy(ch1, s1, i1+1);
  74. return ch1;
  75. }
  76. ch2 = (char *)malloc(i1 + i2 + 1);  // 1 bit '\0'
  77. memset(ch1, '0', i1 + i2 + 2);
  78. ch1[i1+i2+1] = 0;
  79. i = i2;
  80. while ( i > 0 ) {
  81. if ( i >= 8 )           // 和j,每次各可处理8位
  82. dis = 8;
  83. else
  84. dis = i;
  85. i -= dis;
  86. memset(ch2, '0', i1 + i2 + 1);  // ch2每次循环都可能被修改
  87. ch2[i1+i2] = 0;
  88. cp1 = &s1[i1];
  89. cp2 = &s2[i2];
  90. cp3 = &ch2[i1 + i];  //  i1+i2-(i2-i)=i1+i, 每次循环往左移动dis位,表示和记录进位
  91. memcpy(chp, cp2 - i2 + i, dis);
  92. chp[dis] = 0;
  93. j2     = atoi(chp);
  94. j = i1;
  95. while ( j > 0 ) {
  96. if ( j >= 8 )     // 最多8位迭代处理与j2相乘
  97. num = 8;
  98. else
  99. num = j;
  100. cp1 -= num;
  101. memcpy(chp, cp1, num);
  102. chp[num] = 0;
  103. j1       = atoi(chp);
  104. memcpy(chp, cp3, dis);  // cp3记录进位,最多有dis位
  105. chp[dis] = 0;
  106. j3     = atoi(chp);
  107. snprintf(chp, 18, "%lld", j1 * j2 + j3);
  108. j1 = strlen(chp);
  109. memcpy(cp3 -j1 + dis, chp, j1);     // 数据向右对齐
  110. cp3 -= num;  // 定位到下次计算进位可能占据空间的开头地址
  111. j -= num;
  112. }
  113. add(ch1, ch2);   // 将新的计算结果与前面的相加,最后可获得最后结果
  114. }
  115. free(ch2);
  116. return ch1;
  117. }
  118. void add(char *s1, char *s2) {
  119. char *cp1, *cp2, *cp3, *ch;
  120. char chp[18];
  121. int  num, n1, n2;
  122. long long i, j, k;
  123. s2 += strspn(s2, "0");
  124. n1  = strlen(s1);       // make sure n1 > n2
  125. if ( (n2  = strlen(s2)) == 0 )
  126. return;
  127. ch  = (char *)malloc(n1+1);
  128. memset(ch, '0', n1);
  129. ch[n1] = 0;
  130. cp1 = &s1[n1];
  131. cp2 = &s2[n2];
  132. cp3 = &ch[n1 - 1];
  133. while ( n2 > 0 ) {    // must validate enough memory
  134. if ( n2 >= 16 )
  135. num = 16;
  136. else
  137. num = n2;
  138. cp1 -= num;
  139. cp2 -= num;
  140. memcpy(chp, cp1, num);
  141. chp[num] = 0;
  142. i        = atoll(chp);
  143. memcpy(chp, cp2, num);
  144. chp[num] = 0;
  145. j        = atoll(chp);
  146. memcpy(chp, cp3, 1);
  147. chp[1] = 0;
  148. k      = atoll(chp);
  149. snprintf(chp, 18, "%lld", i + j + k);
  150. i = strlen(chp);
  151. cp3 -= i - 1;
  152. memcpy(cp3, chp, i);
  153. cp3 += i - 1 - num;
  154. n2 -= num;
  155. }
  156. memcpy(s1, ch, n1);
  157. free(ch);
  158. }

原文转自 http://blog.csdn.net/chiichen/article/details/6685858

原作者为 chiichen. 请尊重原作者版权

北大OJ 1001题的更多相关文章

  1. acm入门 杭电1001题 有关溢出的考虑

    最近在尝试做acm试题,刚刚是1001题就把我困住了,这是题目: Problem Description In this problem, your task is to calculate SUM( ...

  2. 【Java】深深跪了,OJ题目Java与C运行效率对比(附带清华北大OJ内存计算的对比)

    看了园友的评论之后,我也好奇清橙OJ是怎么计算内存占用的.重新测试的情况附在原文后边. -------------------------------------- 这是切割线 ----------- ...

  3. hdu 5288||2015多校联合第一场1001题

    pid=5288">http://acm.hdu.edu.cn/showproblem.php?pid=5288 Problem Description OO has got a ar ...

  4. Sublime Text3 配置C++(附oj刷题常用模板)

    # 下载对应平台的sublime sublime最新版下载, 字体样式个人喜欢Consolas, 另附注册码: -– BEGIN LICENSE -– TwitterInc 200 User Lice ...

  5. 九度oj 1001 A+B for Matrices 2011年浙江大学计算机及软件工程研究生机试真题

    题目1001:A+B for Matrices 时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:15235 解决:6172 题目描述: This time, you are supposed ...

  6. Leetcode OJ 刷题

    Valid Palindrome吐槽一下Leetcode上各种不定义标准的输入输出(只是面试时起码能够问一下输入输出格式...),此篇文章不是详细的题解,是自己刷LeetCode的一个笔记吧,尽管没有 ...

  7. 九度OJ做题记录 更新.....

    2015年1月7日 20:34:23  题目1007:奥运排序问题 有点意思,以后想另外方法快速做出来 2015年1月7日 21:03:56 有一个技巧就是,写了三个比较函数cmp1,cmp2,cmp ...

  8. 牛客OJ——[编程题]A+B和C__如何输入多组测试数据(测试OK)

    几个要注意的地方: (1)Java OJ,必须将类名写成Main (2)关于如何输入多组测试数据,用二维数组去存储是一个方法,直接在while里面做也可以          但是如果  (3)关于整形 ...

  9. HDU 4738 Caocao's Bridges (2013杭州网络赛1001题,连通图,求桥)

    Caocao's Bridges Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) ...

随机推荐

  1. js中json对象和字符串的转换

    JSON.parse() : 字符串-->json对象 var str = '{"name":"huangxiaojian","age" ...

  2. C 运算符优先级

    优先级 运算符 名称或含义 使用形式 结合方向 说明 1 [] 数组下标 数组名[常量表达式] 左到右   () 圆括号 (表达式)/函数名(形参表)   . 成员选择(对象) 对象.成员名   -& ...

  3. MiniProfiler 兼容 Entity Framework 6

    一直以来都是在用MiniProfiler配合ASP.NET MVC做请求的监控. 在某项目升级Entity Framework 6之后,在执行查询时报错误: --------------无法将类型为“ ...

  4. 教你一招 - 如何给nopcommerce增加一个类似admin的area

    asp.net mvc里面的area是什么,点击这里查看 如果在nopcommerce里面加入类似admin的area,步骤如下: 1.新建一个mvc空项目MvcApplication1,位置放在\N ...

  5. SpringMVC从入门到精通之第二章

    这一章原本我是想写一个入门程序的,但是后来仔细想了一下,先从下面的图中的组件用代码来介绍,可能更效果会更加好一点.第一节:开发准备介绍之前先说下我的开发调试环境:JDK 1.7的64位 .Eclips ...

  6. Lucene TF-IDF 相关性算分公式(转)

    Lucene在进行关键词查询的时候,默认用TF-IDF算法来计算关键词和文档的相关性,用这个数据排序 TF:词频,IDF:逆向文档频率,TF-IDF是一种统计方法,或者被称为向量空间模型,名字听起来很 ...

  7. BZOJ1864[ZJOI2006]三色二叉树[树形DP]

    1864: [Zjoi2006]三色二叉树 Time Limit: 1 Sec  Memory Limit: 64 MBSubmit: 773  Solved: 548[Submit][Status] ...

  8. 第30课 Qt中的文本编辑组件

    1. 3种常用的文本编辑组件的比较 单行文本支持 多行文本支持 自定义格式支持 富文本支持 QLineEdit (单行文本编辑组件) Yes No No No QPlainTextEdit (多行普通 ...

  9. HTML DOM 事件

    HTML DOM 事件 HTML DOM 事件 HTML DOM 事件允许Javascript在HTML文档元素中注册不同事件处理程序. 事件通常与函数结合使用,函数不会在事件发生前被执行! (如用户 ...

  10. http协议.md

    该文转自:HTTP协议详解 HTTP协议详解 引言 超文本传输协议(HTTP,HyperText Transfer Protocol)是互联网上应用最为广泛的一种网络协议.所有的WWW文件都必须遵守这 ...