樓天城之做男人就過八道題(第一題…
阿新 • • 發佈:2019-02-10
關於樓教主的第一題,感覺最費時間的還是高精度的實現。實現一萬位以上整數基本運算的萬進位制高精度模版就寫了快一天(題目裡用到大概也有幾百位吧),只能說太容易出錯了,得不斷地除錯修改。題目源地址是北大poj1737題,題目本身的組合數學的演算法是參考某位大牛的文章,在此附上地址http://hi.baidu.com/accplaystation/item/0b3b4e1654a07548e75e06f9
下面分別是49和50個點時的結果以及原始碼,供參考:
49: 10263013515700550779116289728670421776807355856352253452035361907379108631238572 44548313982876228994987864700400759811456244128889754306386459557887432298148719 59173497103061147469088590424739631395981885494059279529144993759879407051757016 75516079509792662379977972835636452421052447375208813714109600679021766298295142 56225641238164014573644333472284672 50: 57775629806264131981532128463353986108213291999872288565750767218860631769630192 41340682335187078778417692523562748348836783209222917852889522593249600859338855 72481476441044041666245632947630667669900623389069655523344952222114179660086674 25130052344927925607827177068266427605834927592260049347147617842015437801204857 1333436567365397136152469165480980158369042006016
#include "iostream" #include "string" #include "cstring" #include "stdio.h" using namespace std; bool remember[55]; struct bigNumber { int num[100]; int ans; bigNumber() { memset(num,0,sizeof(num)); ans=1; } bigNumber operator =(int k) { int i=0; num[i]=k000; while(k>=10000) { i++; k/=10000; num[i]=k000; } ans=i+1; return *this; } }; bigNumber number[55]; bigNumber bigNumber1,bigNumber2,bigNumber3; ostream& operator << (ostream& os, constbigNumber& big)//輸出高精度數運算子過載 { os<<big.num[big.ans-1]; for(inti=big.ans-2;i>=0;i--) { if(big.num[i]==0) os<<"000"; else if(big.num[i]<10) os<<"000"; else if(big.num[i]<100) os<<"00"; else if(big.num[i]<1000) os<<"0"; os<<big.num[i]; } return os; } istream& operator>>(istream& is, bigNumber &big)//輸入高精度運算子的過載 { string s; is>>s; intlength=s.size(); for(int i=0;i { char a=s[i]; s[i]=s[length-1-i]; s[length-1-i]=a; } int m=1; for(int i=0;i { int a=s[i]-'0'; big.num[i/4]+=a*m; m*=10; if(m==10000) m=1; } big.ans=(length-1)/4+1; return is; } bigNumber operator*(bigNumber big1,bigNumberbig2)//兩個高精度數相乘 { bigNumber big3; for(int i=0;i { for(int j=0;j { inta=big1.num[i]*big2.num[j]; big3.num[i+j]+=a000; big3.num[i+j+1]+=a/10000; } for(int k=i;k<=i+big2.ans;k++) { if(big3.num[k]>=10000) { big3.num[k+1]+=big3.num[k]/10000; big3.num[k]=big3.num[k]000; } } } big3.ans=big1.ans+big2.ans; while(big3.num[big3.ans]==0) big3.ans--; big3.ans++; if(big3.ans==0) big3.ans++; returnbig3; } bigNumber operator*(bigNumber big,intk)//高精度乘以普通常數(注意常數的大小範圍不可太大) { bigNumber tool; for(int i=0;i { int product=big.num[i]*k; tool.num[i]+=product000; int j=i; while(product>=10000) { product/=10000; tool.num[++j]+=product000; } } tool.ans=big.ans+10; while(tool.num[tool.ans]==0) tool.ans--; tool.ans++; big=tool; return big; } bigNumber operator+(bigNumber big1,bigNumberbig2)//兩個高精度數相加,將和賦在第一個數上 { bigNumber tool=big1; for(int i=0;i { tool.num[i]+=big2.num[i]; int j=i; while(tool.num[j]>=10000) { inta=tool.num[j]; tool.num[j]=a000; tool.num[j+1]+=a/10000; j++; } } tool.ans=max(big1.ans+1,big2.ans+1); while(tool.num[tool.ans]==0) tool.ans--; tool.ans++; return tool; } bigNumber operator/(bigNumber &big1,int k) { int i=big1.ans-1; int a; while(i>=0) { a=big1.num[i]; big1.num[i]=0; while(i>0&&a { a*=10000; a+=big1.num[--i]; big1.num[i]=0; } big1.num[i]=a/k; if(i==0) break; if(i>0) big1.num[--i]+=(a%k)*10000; } while(big1.num[big1.ans]==0) big1.ans--; big1.ans++; return big1; } bigNumber function0(int n) { if(n==1||n==2) { bigNumber big; big.num[0]=1; return big; } if(remember[n]) return number[n]; bigNumber tool; for(int k=1;k { bigNumber big1=function0(k); bigNumber big2=function0(n-k); bigNumber big3; big3.num[0]=1; for(int i=n-2;i>n-2-k+1;i--) { big3=big3*i; } for(int i=2;i<=k-1;i++) big3=big3/i; bigNumber big4; big4.num[0]=1; for(int i=1;i<=k;i++) big4=big4*2; big4.num[0]-=1; tool=tool+(big1*big2*big3*big4); } remember[n]=true; number[n]=tool; return tool; } int main() { for(inti=0;i<=50;i++) remember[i]=false; int n; while(scanf("%d",&n)!=EOF&&n!=0) cout<<function0(n)<<endl;; return 0; }
下面分別是49和50個點時的結果以及原始碼,供參考:
49: 10263013515700550779116289728670421776807355856352253452035361907379108631238572 44548313982876228994987864700400759811456244128889754306386459557887432298148719 59173497103061147469088590424739631395981885494059279529144993759879407051757016 75516079509792662379977972835636452421052447375208813714109600679021766298295142 56225641238164014573644333472284672 50: 57775629806264131981532128463353986108213291999872288565750767218860631769630192 41340682335187078778417692523562748348836783209222917852889522593249600859338855 72481476441044041666245632947630667669900623389069655523344952222114179660086674 25130052344927925607827177068266427605834927592260049347147617842015437801204857 1333436567365397136152469165480980158369042006016
#include "iostream" #include "string" #include "cstring" #include "stdio.h" using namespace std; bool remember[55]; struct bigNumber { int num[100]; int ans; bigNumber() { memset(num,0,sizeof(num)); ans=1; } bigNumber operator =(int k) { int i=0; num[i]=k000; while(k>=10000) { i++; k/=10000; num[i]=k000; } ans=i+1; return *this; } }; bigNumber number[55]; bigNumber bigNumber1,bigNumber2,bigNumber3; ostream& operator << (ostream& os, constbigNumber& big)//輸出高精度數運算子過載 { os<<big.num[big.ans-1]; for(inti=big.ans-2;i>=0;i--) { if(big.num[i]==0) os<<"000"; else if(big.num[i]<10) os<<"000"; else if(big.num[i]<100) os<<"00"; else if(big.num[i]<1000) os<<"0"; os<<big.num[i]; } return os; } istream& operator>>(istream& is, bigNumber &big)//輸入高精度運算子的過載 { string s; is>>s; intlength=s.size(); for(int i=0;i { char a=s[i]; s[i]=s[length-1-i]; s[length-1-i]=a; } int m=1; for(int i=0;i { int a=s[i]-'0'; big.num[i/4]+=a*m; m*=10; if(m==10000) m=1; } big.ans=(length-1)/4+1; return is; } bigNumber operator*(bigNumber big1,bigNumberbig2)//兩個高精度數相乘 { bigNumber big3; for(int i=0;i { for(int j=0;j { inta=big1.num[i]*big2.num[j]; big3.num[i+j]+=a000; big3.num[i+j+1]+=a/10000; } for(int k=i;k<=i+big2.ans;k++) { if(big3.num[k]>=10000) { big3.num[k+1]+=big3.num[k]/10000; big3.num[k]=big3.num[k]000; } } } big3.ans=big1.ans+big2.ans; while(big3.num[big3.ans]==0) big3.ans--; big3.ans++; if(big3.ans==0) big3.ans++; returnbig3; } bigNumber operator*(bigNumber big,intk)//高精度乘以普通常數(注意常數的大小範圍不可太大) { bigNumber tool; for(int i=0;i { int product=big.num[i]*k; tool.num[i]+=product000; int j=i; while(product>=10000) { product/=10000; tool.num[++j]+=product000; } } tool.ans=big.ans+10; while(tool.num[tool.ans]==0) tool.ans--; tool.ans++; big=tool; return big; } bigNumber operator+(bigNumber big1,bigNumberbig2)//兩個高精度數相加,將和賦在第一個數上 { bigNumber tool=big1; for(int i=0;i { tool.num[i]+=big2.num[i]; int j=i; while(tool.num[j]>=10000) { inta=tool.num[j]; tool.num[j]=a000; tool.num[j+1]+=a/10000; j++; } } tool.ans=max(big1.ans+1,big2.ans+1); while(tool.num[tool.ans]==0) tool.ans--; tool.ans++; return tool; } bigNumber operator/(bigNumber &big1,int k) { int i=big1.ans-1; int a; while(i>=0) { a=big1.num[i]; big1.num[i]=0; while(i>0&&a { a*=10000; a+=big1.num[--i]; big1.num[i]=0; } big1.num[i]=a/k; if(i==0) break; if(i>0) big1.num[--i]+=(a%k)*10000; } while(big1.num[big1.ans]==0) big1.ans--; big1.ans++; return big1; } bigNumber function0(int n) { if(n==1||n==2) { bigNumber big; big.num[0]=1; return big; } if(remember[n]) return number[n]; bigNumber tool; for(int k=1;k { bigNumber big1=function0(k); bigNumber big2=function0(n-k); bigNumber big3; big3.num[0]=1; for(int i=n-2;i>n-2-k+1;i--) { big3=big3*i; } for(int i=2;i<=k-1;i++) big3=big3/i; bigNumber big4; big4.num[0]=1; for(int i=1;i<=k;i++) big4=big4*2; big4.num[0]-=1; tool=tool+(big1*big2*big3*big4); } remember[n]=true; number[n]=tool; return tool; } int main() { for(inti=0;i<=50;i++) remember[i]=false; int n; while(scanf("%d",&n)!=EOF&&n!=0) cout<<function0(n)<<endl;; return 0; }