洛谷P1255数楼梯(大数,高精度加法)
题目链接:https://www.luogu.org/problemnew/show/P1255
这题挺有意思
首先麻烦的一点,要推出方案数:f[n]=f[n-1]+f[n-2]。
然后还不算完,大数运算开始
long long,unsigned long long,60分
普通高精大数加法过了,但1400ms
1 #include <iostream> 2 #include <string> 3 #include <algorithm> 4 #include <cstdio> 5 #include <cstring> 6 #include <cmath> 7 using namespace std; 8 typedef long long ll; 9 typedef unsigned long long ull; 10 const int maxn=1e6+5; 11 char a[maxn],b[maxn],d[maxn]; 12 int c[maxn]; 13 14 int zfs(char c) 15 { 16 if(c==0) return 0; 17 else if(c>='0' && c<='9') return c-48; 18 else return c-65+10; 19 } 20 21 void Add(int len1,int len2) 22 { 23 //交换工作,倒序 24 int p=-1; 25 for(int i=len1-1;i>=0;i--) d[++p]=a[i]; 26 for(int i=0;i<=len1-1;i++) a[i]=d[i]; 27 p=-1; 28 for(int i=len2-1;i>=0;i--) d[++p]=b[i]; 29 for(int i=0;i<=len2-1;i++) b[i]=d[i]; 30 31 //模拟计算 32 int len=max(len1,len2); 33 for(int i=0;i<=len-1;i++) 34 { 35 int x=zfs(a[i]),y=zfs(b[i]); 36 c[i]+=x+y; 37 while(c[i]>=10) 38 { 39 c[i]-=10; 40 c[i+1]+=1; 41 } 42 } 43 44 //更新操作,重新赋值 45 p=-1; 46 for(int i=len2-1;i>=0;i--) a[++p]=b[i]; 47 p=-1; 48 if(c[len]!=0) b[++p]=c[len]+48; 49 for(int i=len-1;i>=0;i--) b[++p]=c[i]+48; 50 memset(c,0,sizeof(c)); 51 52 //输出 53 if(c[len]!=0) cout<<c[len]; 54 for(int i=len-1;i>=0;i--) cout<<c[i]; 55 cout<<endl; 56 57 } 58 59 int main() 60 { 61 ios::sync_with_stdio(false); cin.tie(0); 62 63 cin>>n; 64 a[0]='1'; 65 b[0]='2'; 66 if(n==0) { cout<<'0'<<endl; return 0; } 67 if(n==1) { cout<<'1'<<endl; return 0; } 68 if(n==2) { cout<<'2'<<endl; return 0; } 69 for(int i=3;i<=n;i++) 70 { 71 int len1=strlen(a),len2=strlen(b); 72 Add(len1,len2); 73 } 74 75 cout<<b<<endl; 76 77 return 0; 78 }
大数加法的一个技巧:
不直接输入运算数时,最好用int数组(这时候可以一个一个存),省去了字符转换的时间
要直接输入运算数时,只能用char数组输入(int多位会错没法计算)
int数组,1300ms(就是交换值更新下一轮的时间太大)
1 #include <iostream> 2 #include <string> 3 #include <algorithm> 4 #include <cstdio> 5 #include <cstring> 6 #include <cmath> 7 using namespace std; 8 typedef long long ll; 9 typedef unsigned long long ull; 10 const int maxn=1e6+5; 11 int a[maxn],b[maxn]; 12 int c[maxn]; 13 int len=1; 14 int n; 15 16 void Add() 17 { 18 //计算 19 for(int i=0;i<=len-1;i++) 20 { 21 c[i]+=a[i]+b[i]; 22 while(c[i]>=10) 23 { 24 c[i]-=10; 25 c[i+1]+=1; 26 } 27 } 28 if(c[len]) len++; 29 30 //更新为了下次轮回(应该就是这里交换很费时间没错了!想办法不要交换用别的方法代替!) 31 for(int i=0;i<=len-1;i++) a[i]=b[i]; 32 for(int i=0;i<=len-1;i++) b[i]=c[i]; 33 memset(c,0,sizeof(c)); 34 } 35 36 int main() 37 { 38 ios::sync_with_stdio(false); cin.tie(0); 39 40 cin>>n; 41 if(n==0) { cout<<'0'<<endl; return 0; } 42 if(n==1) { cout<<'1'<<endl; return 0; } 43 if(n==2) { cout<<'2'<<endl; return 0; } 44 a[0]=1; 45 b[0]=2; 46 for(int i=3;i<=n;i++) 47 { 48 Add(); 49 } 50 51 if(b[len]) cout<<b[len]; 52 for(int i=len-1;i>=0;i--) cout<<b[i]; 53 cout<<endl; 54 55 return 0; 56 }
另一种很不错的大数加法写法107ms(其实就是用二维数组优化了上面的,不用再每轮交换更新赋值了!)
思路大概是用数组f[k][j]来存储走k个阶梯所用的步数 最后循环输出
1 #include <iostream> 2 #include <string> 3 #include <algorithm> 4 #include <cstdio> 5 #include <cstring> 6 #include <cmath> 7 using namespace std; 8 typedef long long ll; 9 typedef unsigned long long ull; 10 const int maxn=1e6+5; 11 int c[maxn]; 12 int f[5005][5005]; 13 int len=1; 14 int n; 15 16 17 void Add(int k) 18 { 19 //计算 20 for(int i=1;i<=len;i++) 21 { 22 f[k][i]+=f[k-1][i]+f[k-2][i]; 23 while(f[k][i]>=10) 24 { 25 f[k][i]-=10; 26 f[k][i+1]+=1; 27 } 28 } 29 30 if(f[k][len+1]) len++; 31 32 } 33 34 int main() 35 { 36 ios::sync_with_stdio(false); cin.tie(0); 37 38 cin>>n; 39 if(n==0) { cout<<'0'<<endl; return 0; } 40 if(n==1) { cout<<'1'<<endl; return 0; } 41 if(n==2) { cout<<'2'<<endl; return 0; } 42 f[1][1]=1; f[2][1]=2; 43 for(int i=3;i<=n;i++) 44 { 45 Add(i); 46 } 47 48 for(int i=len;i>=1;i--) cout<<f[n][i]; 49 cout<<endl; 50 51 return 0; 52 }
完。