UVaOJ 112道题目-组合数学
1、110601/10183 How Many Fibs? (斐波那契计数)
使用字符数组表示数列,double可以表示300位整数,但会出现精度问题。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<stdio.h> #include<string.h> #include<math.h> #include<algorithm> #include<ctype.h> using namespace std; struct NODE { char dig[150]; }nod[1005]; char a[150],b[150]; void rever(char a[]) { int la=strlen(a); for(int i=0;i<la/2;i++) swap(a[i],a[la-1-i]); } int _strcmp(char a[],char b[]) { int la=strlen(a),lb=strlen(b),i; if(la!=lb)return la<lb?-1:1; for(i=la-1;i>=0;i--) { if(a[i]!=b[i])return a[i]>b[i]?1:-1; } return 0; } int main() { strcpy(nod[1].dig,"1"); strcpy(nod[2].dig,"2"); int i=3,j,cnt,t1,t2; for(;;i++) { int len1=strlen(nod[i-2].dig); int len2=strlen(nod[i-1].dig); cnt=0; for(j=0;j<len1||j<len2;j++) { t1=0; t2=0; if(j<len1) t1=nod[i-2].dig[j]-'0'; if(j<len2) t2=nod[i-1].dig[j]-'0'; nod[i].dig[j]=(t1+t2+cnt)%10+'0'; cnt=(t1+t2+cnt)/10; } if(cnt!=0) nod[i].dig[j++]=cnt+'0'; nod[i].dig[j]='\0'; if(j>100)break; } int tot=i; //sort(nod,nod+tot,cmp); while(scanf("%s",a)!=EOF) { scanf("%s",b); if(a[0]=='0'&&b[0]=='0')break; cnt=0; rever(a); rever(b); for(i=0;i<tot;i++) { //printf("%s\n",nod[i].dig); if(_strcmp(a,nod[i].dig)>0)continue; if(_strcmp(b,nod[i].dig)<0)break; cnt++; } printf("%d\n",cnt); } return 0; }
2、110602/10213 How Many Pieces of Land? (土地分割)
使用了欧拉公式,答案是c(n,2)+c(n,4)+1,因为输入的整数是32位,所以还需要使用高精度,高精度的四则运算主要使用数组表示
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<stdio.h> #include<string.h> #include<algorithm> #include<math.h> #include<ctype.h> using namespace std; typedef long long lld; lld n; const int length=1000; int res[length],tr[5][length],ts[length]; void multi(int sa[],int sb[]) { int i,j,x; int st=0,cnt=0,tmp; int num[length]; memset(num,0,sizeof(num)); for(i=0;sb[i]!=-1;i++) { for(j=0;sa[j]!=-1;j++) { tmp=sb[i]*sa[j]; x=num[st+j]; num[st+j]=(x+tmp+cnt)%10; cnt=(x+tmp+cnt)/10; } while(cnt!=0) { x=num[st+j]; num[st+j]=(x+cnt)%10; cnt=(x+cnt)/10; j++; } st++; } i=length-1; while(num[i]==0) { i--; } sa[i+1]=-1; while(i>=0) { sa[i]=num[i]; i--; } } void add(int sa[],int sb[]) { int i,j,cnt=0,ta,tb; bool fa=false,fb=false; for(i=0;!fa||!fb;i++) { ta=sa[i]; tb=sb[i]; if(ta<0)fa=true; if(tb<0)fb=true; ta=ta>0?ta:0; tb=tb>0?tb:0; sa[i]=(ta+tb+cnt)%10; cnt=(ta+tb+cnt)/10; } if(sa[i-1]==0)i--; sa[i]=-1; } void sub(int sa[],int sb[]) { int i,j,ta,tb,cnt=0; bool fa=false,fb=false; for(i=0;!fa||!fb;i++) { ta=sa[i]; tb=sb[i]; if(ta<0)fa=true; if(tb<0)fb=true; ta=ta>0?ta:0; tb=tb>0?tb:0; tb+=cnt; if(ta<tb) { ta+=10; cnt=1; } else cnt=0; sa[i]=ta-tb; } sa[i-1]=-1; } void div(int sa[],int d) { int i=0,tmp=0; while(sa[i]!=-1)i++; bool flag=false; for(i-=1;i>=0;i--) { tmp=tmp*10+sa[i]; if(tmp>=d) { flag=true; printf("%d",tmp/d); tmp=tmp%d; } else { if(flag)printf("0"); } } } void setnum(int sa[],int n) { int i=0; while(n) { sa[i++]=n%10; n/=10; } sa[i]=-1; } int main() { int T; scanf("%d",&T); while(T--) { scanf("%lld",&n); int i; if(n<3) { if(n==0) printf("1\n"); else printf("%d\n",n); continue; } if(n==3) { printf("4\n"); continue; } for(i=0;i<=4;i++)memset(tr,0,sizeof(tr)); setnum(tr[1],n); for(i=2;i<=4;i++) { setnum(tr[i],n); multi(tr[i],tr[i-1]); } setnum(ts,6); multi(tr[3],ts); setnum(ts,23); multi(tr[2],ts); setnum(ts,18); multi(tr[1],ts); setnum(ts,24); add(tr[4],ts); add(tr[4],tr[2]); sub(tr[4],tr[3]); sub(tr[4],tr[1]); div(tr[4],24); printf("\n"); } return 0; }
3、110603/10198 C ounting (数数)
此题使用动态规划,当N为1000时,答案可以达到407位,所以开数组时需要注意,还有在做大数相加时也需要注意
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<stdio.h> #include<string.h> #include<math.h> #include<algorithm> using namespace std; typedef long long lld; const lld INF=1.0e17; struct BigInteger { lld num[30]; void init() { memset(num,0,sizeof(num)); } void add(int t,BigInteger x) { int m=1,i; lld n,cnt=0; if(t==1)m=2; for(i=0;i<30;i++) { n=x.num[i]*m+num[i]+cnt; num[i]=n%INF; cnt=n/INF; } } }dp[1005][1005],ans[1005]; void init() { dp[1][1].init(); dp[1][1].num[0]=2; dp[1][2].init(); dp[1][2].num[0]=1; dp[1][3].init(); dp[1][3].num[0]=1; int i,j; for(i=1;i<1000;i++) { for(j=i;j<=3*i&&j<=1000;j++) { dp[i+1][j+1].add(1,dp[i][j]); dp[i+1][j+2].add(2,dp[i][j]); dp[i+1][j+3].add(3,dp[i][j]); } } for(i=0;i<=1000;i++) { ans[i].init(); for(j=1;j<=i;j++) { ans[i].add(2,dp[j][i]); } } } int main() { int n; init(); while(scanf("%d",&n)!=EOF) //freopen("E:\\a.txt","w",stdout); //for(n=1;n<=1000;n++) { int i=29; while(ans[n].num[i]==0)i--; printf("%lld",ans[n].num[i]); i--; while(i>=0) { printf("%017lld",ans[n].num[i]); i--; } printf("\n"); } return 0; }