51Nod-1946-特殊表示法
2018-01-01 20:28
176 查看
ACM模版
![](http://img.blog.csdn.net/20180101200111078?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZl96eWo=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
至此,我们来考虑两个序列叠加在一起后可能存在的情况。首先 A 和 B 都用特殊表示法表示,叠加在一起,则可能存在某一下出现 0、1、2 次,我们需要考虑将大于 1 的和连着两个 1 的转化一下,大于 1 的我们可以转化为两个一个大一些的和一个小一些的项之和,而连着两个 1 的则可以转化为更大的一项。对于前者我们逆着来,后者我们正着来,就差不多了。
但是此时提交还会有 bug,这也是这道题 AC 率那么低的原因,有些地方不容易想到,下载数据一看会发现自己漏考虑情况了。不容易想到的地方大致有两点,一是存在大于 2 的情况发生,这个是因为当我们在进行第一个转化过程时,会有加项操作,所以会出现大于 2 的情况,其次是边界问题需要考虑一下,具体的看一下代码吧,代码中注释写得十分清楚了。
可以加上输入输出外挂优化一下,我比较懒,只是将输出部分先存在字符串然后统一输出了一下,节约了一些时间,输入的时候也可以整行读入然后处理一下,比较容易,但是架不住我懒。
描述
题解
首先我们来分析一下斐波那契数列的基本性质,众所周知,斐波那契数列从第二项开始后,能够组合(每一项只有选与不选两种操作)出来任意自然数,所以才会有这个特殊表示法的存在,并且这个表示法里不存在任意两个连着的 1,因为一旦存在就可以转化为另一个数,毕竟 fib[i]=fib[i−1]+fib[i−2],如果 i−1 项和 i−2 项都选了,那就可以转化为 i 项。至此,我们来考虑两个序列叠加在一起后可能存在的情况。首先 A 和 B 都用特殊表示法表示,叠加在一起,则可能存在某一下出现 0、1、2 次,我们需要考虑将大于 1 的和连着两个 1 的转化一下,大于 1 的我们可以转化为两个一个大一些的和一个小一些的项之和,而连着两个 1 的则可以转化为更大的一项。对于前者我们逆着来,后者我们正着来,就差不多了。
但是此时提交还会有 bug,这也是这道题 AC 率那么低的原因,有些地方不容易想到,下载数据一看会发现自己漏考虑情况了。不容易想到的地方大致有两点,一是存在大于 2 的情况发生,这个是因为当我们在进行第一个转化过程时,会有加项操作,所以会出现大于 2 的情况,其次是边界问题需要考虑一下,具体的看一下代码吧,代码中注释写得十分清楚了。
可以加上输入输出外挂优化一下,我比较懒,只是将输出部分先存在字符串然后统一输出了一下,节约了一些时间,输入的时候也可以整行读入然后处理一下,比较容易,但是架不住我懒。
代码
#include <iostream> #include <cstdio> using namespace std; const int MAXN = 1e6 + 5; int n, m; int a[MAXN]; int b[MAXN]; char c[MAXN << 1]; int main() { scanf("%d", &n); getchar(); for (int i = 0; i < n; i++) { a[i] = getchar() - '0'; getchar(); } scanf("%d", &m); getchar(); for (int i = 0; i < m; i++) { a[i] += getchar() - '0'; getchar(); } // 逆着扩展一遍 n = max(m, n); for (int i = n - 1; i > 1; i--) { if (a[i] >= 2) { // ex: 2 * 5 = 8 + 2 a[i] -= 2; a[i - 2] += 1; a[i + 1] += 1; n = max(i + 2, n); } if (a[i] >= 1 && a[i - 1] >= 1) { // ex: 2 + 3 = 5 a[i] -= 1; a[i - 1] -= 1; a[i + 1] += 1; n = max(i + 2, n); } } // 处理边界特殊情况 if (a[0] >= 2 && a[1] == 0) { // ex: 1 + 1 = 2 a[0] -= 2; a[1] += 1; } else if (a[1] == 3) { // ex: 2 + 2 + 2 = 1 + 2 + 3 a[1] -= 1; a[0] += 1; a[2] += 1; } // 正着扩展若干遍,一直到无法扩展 int flag = 1; while (flag) { flag = 0; for (int i = 0; i < n; i++) { if (a[i] >= 1 && a[i + 1] >= 1 && a[i + 2] != 1) { flag = 1; // ex: 2 + 3 = 5 a[i] -= 1; a[i + 1] -= 1; a[i + 2] += 1; n = max(i + 3, n); } } } int cnt = 0; for (int i = 0; i < n; i++) { c[cnt++] = a[i] + '0'; if (i != n - 1) { c[cnt++] = ' '; } } c[cnt] = '\n'; printf("%d\n%s", n, c); return 0; }
相关文章推荐
- 51nod 特殊表示法
- 特殊符号在html中的表示
- 51Nod 1241 特殊的排序
- 学习日志---矩阵表示及特殊矩阵压缩
- 集合论——集合表示方法,关系及特殊集合
- android[xml]Android strings.xml中空格符的标识方法附xml特殊字符表示法
- 一种特殊节点的XPATH表示
- xml 特殊字符的表示
- C语言--指针--输入字符串,以特殊字符结尾并打印出输入的字符串(自动去除结尾表示字符串)
- shell的特殊符号的表示
- [斐波那契拆分 乱搞 数学] 51Nod 1350 斐波那契表示
- html中特殊符号表示
- 特殊符号在html中的表示
- 51nod 1241 特殊的排序(锻炼思维的好题)
- c#中的特殊字符表示问题
- iOS 中的特殊字面量表示方法
- 51Nod - 1821:最优集合 (求第一个不能被表示为多个数的和的数)(不错的动脑题)
- 表示字符集的特殊字符
- 51Nod - 1241 特殊的排序(求最长连续递增子序列)
- 51nod---无法表示的数