这题叫Train Problem II,看到题目第一反应和前一个题一样,估计是用栈做然后加一些什么花样吧,然后读完题发现,这题用栈做肯定是超时的= =题意就是说输入一个数,然后以上一题的思路,求出这个数量的数出栈有多少种情况......直接用栈是肯定不行的了= =拿出纸笔老实找找有什么规律吧
至于找的规律,感觉和dp思想差不多= =已经知道1个数1种排列,2个数2种排列,3个数5种排列了。那么看4个数,假设是1234的顺序等候进栈,把他拆分开,假如最后出栈的是4,那么就是排列123有几种排列,是5种。再假如最后出栈的是3,排列12有2种排序,排列4只有1种排序,总共就是2×1种排序。同样的再推出2为分界的时候是2种,1为分界的时候是5种,加起来得到14种,就是4个数的排列了。用一个数组把他们储存起来,然后a[4]这样就赋值为14了。继续再用同一个思想拆分5个数,这样规律算是找到了,代码也很好写,跑两个循环就够了。
然而,这题的麻烦还没结束,虽然心里知道最后数一定会很大,long long不一定能够,但是我还是先用long long打了一个表看看,心想要是剩几个数出不来就直接手算剩下几个就算了= =然而打完表后发现打到35就打不下去了......算了,还是慢慢用字符串写大数相加相乘吧= =
下面先贴上我long long打表的程序:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
long long a[105];
int main()
{
a[0]=1;
a[1]=1;
long long sum=0;
int n;
int i,j;
for(i=2;i<100;i++)
{
for(j=i;j>0;j--)
{
sum=sum+a[i-j]*a[j-1];
}
a[i]=sum;
sum=0;
cout<<"a["<<i<<"] = "<<a[i]<<endl;
}
return 0;
}
//打表就会发现,到35就已经long long存不下去了
再之后就是写大数相加相乘了,第一次写这是一项大工程啊= =思路没什么好说的,就按着小学算加法乘法的方式写代码就行了,然后char和int之间相互记得转换一下,最后从1到100打个表,打出来这个表之后输入n是几对着表输出几就行了。我是写了三个函数,一个加法的函数,一个乘法的函数,以及一个打表,思路没什么说的了,下面看代码吧就~
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<stack>
using namespace std;
char ans[105][1005];
char ads[105],mus[105];
int multiply(char* a1,char* b1)
{
memset(mus,0,sizeof(mus));
int i,j,k;
int len,len1,len2;
len1=strlen(a1);
len2=strlen(b1);
int mut=0,t;
bool va[105];
int s[105],adt[105];
char a[105],b[105];
memset(s,0,sizeof(s));
memset(adt,0,sizeof(adt));
memset(va,0,sizeof(va));
for(i=len1-1,j=0;i>=0;i--)
{
a[i]=a1[j];
j++;
}
for(i=len2-1,j=0;i>=0;i--)
{
b[i]=b1[j];
j++;
}
for(i=0;i<len1;i++)
{
mut=0;
for(j=0;j<len2;j++)
{
t=(a[i]-'0')*(b[j]-'0')+mut;
mut=0;
if(t>=10)
{
mut=t/10;
t=t%10;
}
s[i+j]=t+s[i+j]+adt[i+j];
va[i+j]=1;
adt[i+j]=0;
if(s[i+j]>=10)
{
if(!va[i+j+1])
adt[i+j+1]=s[i+j]/10+adt[i+j+1];
else
adt[i+j+1]=s[i+j]/10;
s[i+j]=s[i+j]%10;
}
}
s[i+j]=mut;
}
s[i+j-1]=mut+adt[i+j-1];
if(s[i+j-1]!=0)
k=i+j-1;
else
k=i+j-2;
for(i=k,j=0;i>=0;i--)
{
mus[i]=(s[j]+'0');
j++;
}
return 0;
}
int additive(char* a,char* b)
{
memset(ads,0,sizeof(ads));
int len,len1,len2;
int i;
int ad[105];
len1=strlen(a);
len2=strlen(b);
if(len1==len2)
{
len=len1;
}
else if(len1>len2)
{
len=len1;
for(i=len;i>=len-len2;i--)
{
b[i]=b[i-len+len2];
}
for(i=len-len2-1;i>=0;i--)
{
b[i]='0';
}
}
else if(len1<len2)
{
len=len2;
for(i=len;i>=len-len1;i--)
{
a[i]=a[i-len+len1];
}
for(i=len-len1-1;i>=0;i--)
{
a[i]='0';
}
}
int t=0;
for(i=len-1;i>=0;i--)
{
ad[i]=(a[i]-'0')+(b[i]-'0')+t;
t=0;
if(ad[i]>=10)
{
t++;
ad[i]=ad[i]-10;
ads[i]=ad[i]+'0';
}
else
{
ads[i]=ad[i]+'0';
}
}
if(t==1)
{
for(i=len;i>=0;i--)
{
ads[i]=ads[i-1];
}
ads[0]='1';
}
return 0;
}
int excel()
{
ans[0][0]='1';
ans[1][0]='1';
char sum[105];
int n;
int i,j;
memset(sum,0,sizeof(sum));
for(i=2;i<=100;i++)
{
for(j=i;j>0;j--)
{
multiply(ans[i-j],ans[j-1]);
additive(mus,sum);
strcpy(sum,ads);
}
strcpy(ans[i],sum);
memset(sum,0,sizeof(sum));
}
return 0;
}
int main()
{
int n;
excel();
while(scanf("%d",&n)!=EOF)
{
cout<<ans[n]<<endl;
}
return 0;
}
本文解析了TrainProblemII的解题方法,采用DP思想找到数列排列的规律,并通过大数运算解决数值溢出问题。
309

被折叠的 条评论
为什么被折叠?



