Problem B
Accepts: 1408 Submissions: 5317
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Problem Description
度熊面前有一个全是由1构成的字符串,被称为全1序列。你可以合并任意相邻的两个1,从而形成一个新的序列。对于给定的一个全1序列,请计算根据以上方法,可以构成多少种不同的序列。
Input
这里包括多组测试数据,每组测试数据包含一个正整数N,代表全1序列的长度。
1\leq N \leq 2001≤N≤200
Output
对于每组测试数据,输出一个整数,代表由题目中所给定的全1序列所能形成的新序列的数量。
Sample Input
1
3
5
Sample Output
1
3
8
Hint
如果序列是:(111)。可以构造出如下三个新序列:(111), (21), (12)。
分析:
和资格赛的第二题一样,直接用递推即可。再考虑第n个(最后一个)1时,(1):他不合并,剩下的n-1个可以按规定合并,所以a[n]=a[n-1];(2):他与第n-1个1合并,剩下的n-2个可以按规定合并。所以a[n]=a[n-1]+a[n-2];
需要注意的是:题目N<200,所以要考虑到高进度加法问题。以下有两种高精度加法(由于200还是很小的所以第一种也可以)。第二种是实现一个大整数类,可以达到第10000位,使他支持高精度加法,有点难度,建议读者慢慢研究体会。
方法一:
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int maxn = 1005;
int a[maxn][maxn];
void init(int a[maxn][maxn])
{
memset(a,0,sizeof(a));
a[1][0] = 1;
a[2][0] = 2;
for(int i = 3; i <= 1002; i++)
{
for(int j = 0; j < maxn ; j++) { a[i][j] += a[i-1][j] + a[i-2][j]; if(a[i][j] >= 10)
{
a[i][j] -= 10;
a[i][j+1]++;
}
}
}
}
int main()
{
int n,i;
init(a);
while(scanf("%d", &n) != EOF)
{
for(i = 1000; i >= 0; i--)
if(a[n][i]) break;
for(; i >= 0; i--)
printf("%d",a[n][i]);
printf("\n");
}
return 0;
}
方法二:
#include <iostream>
#include <string.h>
#include <cstdio>
using namespace std;
const int MAXN = 100000000;
const int N = 500;
const int M = 10000;
struct bign {
int len;
int s[N];
bign() {
this -> len = 1;
memset(s, 0, sizeof(s));
}
bign (int number) {*this = number;}
bign (const char* number) {*this = number;}
bign change(bign cur) {
bign now;
now = cur;
for (int i = 0; i < cur.len; i++) now.s[i] = cur.s[cur.len - i - 1]; return now; } void delZore() { // 删除前导0.
bign now = change(*this); while (now.s[now.len - 1] == 0 && now.len > 1) {
now.len--;
}
*this = change(now);
}
void put() { // 输出数值。
delZore();
printf("%d", s[0]);
for (int i = 1; i < len; i++)
printf("%08d", s[i]);
}
bign operator = (const char *number) {
memset(s, 0, sizeof(s));
int dist = strlen(number);
int k = dist % 8;
for (int i = 0; i < k; i++)
s[0] = s[0] * 10 + number[i] - '0';
int cnt = 0;
for (int i = k; i < dist; i++, cnt++)
s[cnt / 8 + 1] = s[cnt / 8 + 1] * 10 + number[i] - '0';
len = cnt / 8 + 1;
return *this;
}
bign operator = (int number) {
char string[N];
sprintf(string, "%d", number);
*this = string;
return *this;
}
bign operator + (const bign &cur){
bign sum, a, b;
sum.len = 0;
a = a.change(*this);
b = b.change(cur);
for (int i = 0, g = 0; g || i < a.len || i < b.len; i++){
int x = g;
if (i < a.len) x += a.s[i];
if (i < b.len) x += b.s[i];
sum.s[sum.len++] = x % MAXN;
g = x / MAXN;
}
return sum.change(sum);
}
};
bign num[M + 10];
int main() {
int n;
num[1]=1;
num[2]=2;
num[3]=3;
num[4]=5;
for (int i = 5; i < M + 5; i++)
num[i] = num[i - 1] + num[i - 2];
while (scanf("%d", &n) == 1) {
num[n].put();
printf("\n");
}
return 0;
}