试题 算法提高 研究兔子的土豪
资源限制
时间限制:1.0s 内存限制:256.0MB
问题描述
某天,HWD老师开始研究兔子,因为他是个土豪
,所以他居然一下子买了一个可以容纳10^18代兔子的巨大笼子(好像比我们伟大的地球母亲大一点点?),并开始研究它们,之后,他了解了兔子的繁衍规律:即fibonacci数列。
兔子繁殖了n代后,HWD老师很开心。
但是,HWD老师有密集恐惧症,所以,他只能去卖了兔子,他找到了一个好的雇主,但是这个雇主有强迫症,他只每次收购1007只兔子,HWD老师为了避免自己的密集恐惧症,要尽量多的卖了兔子。
但是即便是密集恐惧症,也打击不了HWD老师研究兔子的决心,他数着数着自己剩下的兔子……
输入格式
HWD老师让兔子繁衍了几代(一个整数,没有其他字符)。
输出格式
HWD老师剩余(残余?)的兔子(一个整数,忽略行尾回车及空格)。
样例输入
1
样例输出
1
数据规模和约定
兔子的总量最大时小于HWD老师笼子的大小。
f[1]=1,f[2]=1,f[3]=2 ……
解题思路:/*难点一:高精度算法求斐波那契数列 ;难点二:最后的兔子总量里面究竟有多少整数个1007可以减去。
难点一,我的解决办法是用f0,f1,f2,三个向量,其中f2表示当前第i代兔子总量,f1表示当前第(i-1)代兔子总量,f0表示当前第(i-2)代兔子总量,每次繁衍前,上一次f2清空,随后f2=f0+f1,得到f2后,向后更新f0=f1、f1=f2。
难点二,我的解法是最后得到f2,然后用f2不断减去1007,直到f2<1007为止,然而,这个算法跑了30分, 碰到n>100就超时了。*/思索再三,我想到,正解应该是在每次繁衍后能减就减去1007。未完待续。。。
二更:啊2333,我一开始就想复杂了,完全可以用long long表示数列元素,同样f2=f0+f1(f2%=1007),然后在更新f0、f1,如此循环,跑了50分,最后还是逃不了超时。。。
original代码如下:
#include <iostream>
#include <vector>
#include <sstream>
#include <cmath>
using namespace std;
vector<long long > f0;
vector<long long > f1;
vector<long long > f2;
long long n;
void updateF2(){
for(int i=0;i<f2.size();i++){
if(f2[i]>=10){
if(i<f2.size()-1)//i不是最高位下标
f2[i+1]+=f2[i]/10;
else
f2.push_back(f2[i]/10);
f2[i]%=10;
}
if(f2[i]<0){
f2[i]+=10;
f2[i+1]--;
}
}
for(int i=f2.size()-1;i>=0;i--){
if(f2[i]==0)
f2.pop_back();
else
break;
}
}
void Print(){
for(int i=f2.size()-1;i>=0;i--){
cout<<f2[i];
}
cout<<endl;
}
void getF2(){
f2.clear();
long long p0=0,p1=0;
while((p0<=f0.size()-1) && (p1<=f1.size()-1) ){
f2.push_back(f0[p0++]+f1[p1++]);
}
if(p0<=f0.size()-1){
f2.push_back(f0[p0++]);
}
if(p1<=f1.size()-1){
f2.push_back(f1[p1++]);
}
updateF2();
//f2=f0+f1后, 更新f0=f1, f1=f2
f0.clear();
for(int i=0;i<f1.size();i++){
f0.push_back(f1[i]);
}
f1.clear();
for(int i=0;i<f2.size();i++){
f1.push_back(f2[i]);
}
}
long long getCurNum(){
long long num=0;
int cnt=f2.size()-1;
for(int i=f2.size()-1;i>=0;i--){
num+=f2[i]*pow(10,cnt--);
}
return num;
}
void massiveMinus(){
// cout<<"start to massiveMinus"<<endl;
while(f2.size()>=11){
f2[6]-=7;
f2[9]-=1;
updateF2();
// cout<<"in >=11"<<endl;
}
while(f2.size()>=10){
f2[5]-=7;
f2[8]-=1;
updateF2();
// cout<<"in >=10"<<endl;
}
// cout<<"after 6"<<endl;
while(f2.size()>=9){
f2[4]-=7;
f2[7]-=1;
updateF2();
}
// cout<<"after 5"<<endl;
while(f2.size()>=8){
f2[3]-=7;
f2[6]-=1;
updateF2();
}
// cout<<"after 4"<<endl;
while(f2.size()>=7){
f2[2]-=7;
f2[5]-=1;
updateF2();
}
// cout<<"after 3"<<endl;
while(f2.size()>=6){
f2[1]-=7;
f2[4]-=1;
updateF2();
}
// cout<<"after 2"<<endl;
while(f2.size()>=5){
f2[0]-=7;
f2[3]-=1;
updateF2();
}
// cout<<"after 1"<<endl;
if(f2.size()<=4){
long long num=0;
while(1){
if(getCurNum()<1007){
num=getCurNum();
break;
}
f2[0]-=7;
f2[3]-=1;
updateF2();
}
cout<<num<<endl;
}
}
int main(int argc, char** argv) {
cin>>n;
f0.push_back(1);
f1.push_back(1);
for(int i=3;i<=n;i++){
getF2();
}
if(n<17){//直接输出f2
if(n<=2)
cout<<"1"<<endl;
else
Print();
}
else{//f2减去1007*(f2/1007),在输出
// cout<<"先打印f2"<<endl;
// Print();
massiveMinus();
}
// long long a=1007;
// cout<<1007*100000<<endl;
return 0;
}
二更代码如下:
#include <iostream>
using namespace std;
long long n;
long long f0,f1,f2;
void getF2(){
f2=f0+f1;
if(f2>1007){
f2%=1007;
}
f0=f1;
f1=f2;
}
int main(int argc, char** argv) {
f0=1,f1=1;
cin>>n;
if(n<3){
cout<<"1"<<endl;
}
else{
for(long long i=3;i<=n;i++){
getF2();
}
cout<<f2<<endl;
}
return 0;
}