1 条题解
-
0
解题思路
-
斐波那契数列:题目要求计算斐波那契数列的前10000项。斐波那契数列的定义为:F(1) = 1, F(2) = 1, F(n) = F(n-1) + F(n-2) (n > 2)。
-
大数运算:由于斐波那契数列增长非常快,普通数据类型无法存储,因此需要使用大数类(HugeInt)来处理高精度计算。
-
结果计算:对于输入的n,根据其奇偶性进行不同计算:
- 如果n是奇数,计算结果为:
(2*F(n)^2 - 1)^2 * 4
- 如果n是偶数,计算结果为:
(2*F(n)^2 + 1)^2 * 4
- 如果n是奇数,计算结果为:
-
格式化输出:结果需要按千分位格式输出(每三位用逗号分隔)。
标程代码
#include<cmath> #include<cstring> #include<algorithm> #include<cstdio> #include<iostream> using namespace std; const int D = 10000; // 大数类每四位一组 // 大数类定义与实现 class HugeInt { public: int len; // 位数 int a[2500]; // 每四位存储一个单元 HugeInt(); HugeInt operator+(const HugeInt&); HugeInt operator+(int); HugeInt operator-(const HugeInt&); HugeInt operator-(int); HugeInt operator*(const HugeInt&); HugeInt operator*(int); void output(); }; // 构造函数:初始化大数为0 HugeInt::HugeInt() { len = 1; memset(a,0,sizeof(a)); } // 大数加整数 HugeInt HugeInt::operator+(int x) { HugeInt ret = *this; ret.a[0] += x; for(int i = 0; i < ret.len - 1 && ret.a[i] >= D; i++) { ret.a[i+1] += ret.a[i] / D; ret.a[i] %= D; } while(ret.a[ret.len-1] >= D) { ret.a[ret.len] += ret.a[ret.len-1] / D; ret.a[ret.len-1] %= D; ret.len++; } return ret; } // 大数加大数 HugeInt HugeInt::operator+(const HugeInt &x) { HugeInt ret = *this; ret.len = max(ret.len, x.len); for(int i = 0; i < ret.len ; i++) { ret.a[i] += x.a[i]; if(ret.a[i] >= D) { ret.a[i+1]++; ret.a[i] -= D; } } if(ret.a[ret.len] > 0) ret.len++; return ret; } // 大数减整数 HugeInt HugeInt::operator-(int x) { HugeInt ret = *this; ret.a[0] -= x; for(int i = 0; i < ret.len && ret.a[i] < 0; i++) { ret.a[i+1] += (ret.a[i] - D + 1) / D; ret.a[i] -= (ret.a[i] - D + 1) / D * D; } while(ret.a[ret.len-1] == 0 && ret.len > 1) ret.len--; return ret; } // 大数减小数(假设被减数大于减数) HugeInt HugeInt::operator-(const HugeInt &x) { int i; HugeInt ret = *this; for(i = 0; i < x.len; i++) { ret.a[i] = ret.a[i] - x.a[i]; if(ret.a[i] < 0) { ret.a[i+1]--; ret.a[i] += D; } } while(ret.a[i] < 0) { ret.a[i] += D; ret.a[++i]--; } while(ret.a[ret.len-1] == 0 && ret.len > 1) ret.len--; return ret; } // 大数乘整数 HugeInt HugeInt::operator*(int x) { HugeInt ret = *this; ret.a[0] *= x; for(int i = 1; i < ret.len; i++) { ret.a[i] *= x; if(ret.a[i-1] >= D) { ret.a[i] += ret.a[i-1] / D; ret.a[i-1] %= D; } } while(ret.a[ret.len-1] >= D) { ret.a[ret.len] += ret.a[ret.len-1] / D; ret.a[ret.len-1] %= D; ret.len++; } while(ret.a[ret.len-1] == 0 && ret.len > 1) ret.len--; return ret; } // 大数乘大数 HugeInt HugeInt::operator*(const HugeInt &x) { HugeInt ret; ret.len = len + x.len - 1; for(int i = 0; i < len; i++) { for(int j = 0; j < x.len; j++) { ret.a[i+j] += a[i] * x.a[j]; if(ret.a[i+j] >= D) { ret.a[i+j+1] += ret.a[i+j] / D; ret.a[i+j] %= D; } } } if(ret.a[ret.len] > 0) ret.len++; while(ret.a[ret.len-1] == 0 && ret.len > 1) ret.len--; return ret; } // 格式化输出大数(每三位用逗号分隔) void HugeInt::output() { int i, j, k = 0; char str[10000]; for(i = len - 1; i >= 0; i--) for(j = 1000; j > 0; j /= 10) str[k++] = a[i] / j % 10 + '0'; for(i = 0; str[i] == '0'; i++); if(i == k) cout << "0" << endl; else if(k - i <= 3) { while(i < k) cout << str[i++]; cout << endl; } else { int cnt = (k - i) % 3; if(cnt == 0) cnt = 3; for(j = i; j < i + cnt; j++) cout << str[j]; for( ; j < k; j += 3) cout << ',' << str[j] << str[j+1] << str[j+2]; cout << endl; } } // 预计算斐波那契数列的前10000项 HugeInt fib[10002]; int main() { // 初始化斐波那契数列 fib[1] = fib[1] + 1; // F(1) = 1 for(int i = 2; i <= 10000; i++) fib[i] = fib[i-1] + fib[i-2]; // F(n) = F(n-1) + F(n-2) int n; while(cin >> n) { HugeInt ret; // 根据n的奇偶性进行不同计算 if(n % 2) ret = fib[n] * fib[n] * 2 - 1; // 奇数情况 else ret = fib[n] * fib[n] * 2 + 1; // 偶数情况 ret = ret * ret * 4; // 统一计算:结果的平方乘以4 ret.output(); // 格式化输出结果 } return 0; }
代码解释
-
HugeInt类:实现了大数的基本运算,包括加减乘。采用每四位一组的存储方式,提高计算效率。
-
斐波那契数列计算:使用动态规划方法预计算前10000项斐波那契数,存储在数组
fib
中。 -
结果计算:
- 对于奇数n,计算
(2*F(n)^2 - 1)^2 * 4
- 对于偶数n,计算
(2*F(n)^2 + 1)^2 * 4
- 对于奇数n,计算
-
输出格式化:将结果转换为字符串,并按每三位添加一个逗号的格式输出。
关键点说明
-
大数乘法优化:采用分块存储(每四位一组),减少乘法运算次数。
-
斐波那契数列的预计算:提前计算并存储所有可能用到的斐波那契数,避免重复计算。
-
奇偶性判断:根据n的奇偶性选择不同的计算公式,确保结果正确性。
-
千分位格式化:输出时自动添加逗号分隔符,符合题目要求的格式。
这个标程能够高效处理大数计算,并正确输出结果,满足题目要求。
-
- 1
信息
- ID
- 2473
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 5
- 已通过
- 1
- 上传者