-
c++可以动态定义数组大小。如
int n;
cin>>n;
int a[n];
是允许的,而c语言不允许这样做 -
全局数组会将数组全部自动初始化为0,而局部定义的数组不会。由于int类型是4字节即2^2, 最大限制为65536KB的内存即2^26B,允许申请大约1600万大小的int类型数组。
-
首先应该分清无限小数和有限小数,并设置数组来存储余数,变量remainder存储余数。那么怎么判断什么时候存在循环呢?一个好方法是检查余数寄存器的值是否已经出现过,如果以前出现过,可以断定再作除法一定会陷入循环。判断余数是否出现过的方法,可以设置一个数组存储,然后每次查找看看能不能找到,但这样也太傻了吧。可以利用哈希的思想,由于余数不会超过100,设置一个hash[100]初值为0,若余数为35,直接修改hash[35],因此出现了新的remainder时,可以通过检验hash[remainder]的值是否为0来判断remainder有没有出现过。最后个一个问题是解决循环节开始和结束位置的问题。因此,可以在出现新的remainder时,将hash[remainder]改为循环的次数i+1,意为下次循环就是remainder循环节的开始,begin=i+1。同时,若某次循环得到的remainder以前已经出现过,那么此时的循环i就是remainder的结束位置,end=i。
#include<bits/stdc++.h>
using namespace std;
int m,n;//calculate m/n,m<n
int main()
{
int quotient[1100],remainder;//商,余数
int flag=0;//标记是否为无限小数
int hash[110]={0};//用哈希来标记这个余数以前是否已经存在,若存在则数组值不为0
int i,len,begin,end;//len记录商的长度
cin>>m>>n;
for(i=1,remainder=m;;i++)
//两种情况结束循环:1找到了循环节。 2,余数为0,除法结束。
{
if(remainder<n)quotient[i]=0;//不够除,则此次商为0
else
{
quotient[i]=remainder/n;
remainder=remainder%n;
}
if(remainder==0)//余数为0,除法结束。
{
flag=1;
len=i;
break;
}
if(hash[remainder]==0)hash[remainder]=i+1;//开始位置为i+1
else //找到循环节了
{
begin=hash[remainder];//开始位置
end=i;//结束位置
break;
}
remainder*=10;//每次除法结束,remainder需要自动乘10,在最后执行
}
cout<<"0.";
if(flag==0)//意思是除不尽
{
for(i=2;i<=end;i++)
cout<<quotient[i];
cout<<endl<<"the begin and end is"<<begin<<" "<<end;
}
else//不是循环小数,可以除尽
{
for(i=2;i<=len;i++)
cout<<quotient[i];
}
}
- 10:大整数加法
查看 提交 统计 提问
总时间限制: 1000ms 内存限制: 65536kB
描述
求两个不超过200位的非负整数的和。
输入
有两行,每行是一个不超过200位的非负整数,可能有多余的前导0。
输出
一行,即相加后的结果。结果里不能有多余的前导0,即如果结果是342,那么就不能输出为0342。
样例输入
22222222222222222222
33333333333333333333
样例输出
55555555555555555555
用数组来存储两个数,由于家数位数较多,只能用字符串类型输入。由于计算是需要右对齐,但是输入的时候最低位储存的是数位的最高位,无法处理进位问题,因此需要对数组做出处理。
将数字全部移动到右对齐。
例如输入数字00598,066,将其移位为
0000000000…00598和00000000000…66需要注意的是,由于两个输入数都不超过200位,也就是最多200位,因此它们的和最多可能是201位,至少要用201位的数组来存储。
0 0 5 9 8
s[0] s[1] s[2] s[3] s[4] 转换为:
0 0 0 0 0 5 9 8
s[0] s[1] s[2] s[3] s[4] …s[198] s[199] s[200]
转换后每个数字的最低位都保存在s[200]这个位置上,总共201位。
最后需要注意0+0=0,0也是要输出的
#include <bits/stdc++.h>
using namespace std;
int a[202],b[202];
char s[201];
int main()
{
int i,j,l1,l2,temp,flag=0;
//因为是全局数组,a和b其他位全是0,在做加法时不用考虑两个数的长度大小,可以一路加下去
cin>>s;
l1=strlen(s);
for(i=l1-1;i>=0;i--)
a[201+i-l1]=s[i]-'0';//字符转换数字
cin>>s;
l2=strlen(s);
for(i=l2-1;i>=0;i--)
b[201+i-l2]=s[i]-'0';
for(i=200,temp=0;i>=0;i--)//从200位开始一直加到0,temp是进位
{
a[i]+=b[i]+temp;
temp=a[i]/10;
a[i]=a[i]%10;
}
for(i=0;i<=200;i++)
{
if(flag==0&&a[i]!=0)flag=1;
if(flag==1)cout<<int(a[i]);
if(i==201&&flag==0)cout<<0;
}
}
- 11:大整数减法
查看 提交 统计 提问
总时间限制: 1000ms 内存限制: 65536kB
描述
求两个大的正整数相减的差。
输入
共2行,第1行是被减数a,第2行是减数b(a > b)。每个大整数不超过200位,不会有多余的前导零。
输出
一行,即所求的差。
样例输入
9999999999999999999999999999999999999
9999999999999
样例输出
9999999999999999999999990000000000000
同上题思路类似,但处理数组稍有不同例如输入564 78,先将564和78转为46500000…000和8700000…0000然后相减后倒序输出。输出时同样用flag标志第一个不为0的数。
#include <bits/stdc++.h>
using namespace std;
int a[201],b[201];
char s[201];
int main()
{
int i,j,l1,l2,flag=0,temp;
cin>>s;
l1=strlen(s);
for(i=0;i<l1;i++)
a[l1-i-1]=s[i]-'0';//处理a
cin>>s;
l2=strlen(s);
for(i=0;i<l2;i++)
b[l2-i-1]=s[i]-'0';//处理b
for(i=0,temp=0;i<l1;i++)
{
//temp是借位
if(a[i]>=b[i]+temp)
{
a[i]-=b[i]+temp;
temp=0;//够减,借位为0
}
else
{//不够减,借位乘10加上去
a[i]=10+a[i]-b[i]-temp;
temp=1;//借位为1
}
}
for(i=199;i>=0;i--)//倒序输出
{
if(a[i]!=0&&flag==0)flag=1;
if(flag==1)cout<<a[i];
}
}
- 13:大整数的因子
查看 提交 统计 提问
总时间限制: 1000ms 内存限制: 65536kB
描述
已知正整数k满足2<=k<=9,现给出长度最大为30位的十进制非负整数c,求所有能整除c的k。
输入
一个非负整数c,c的位数<=30。
输出
若存在满足 c%k == 0 的k,从小到大输出所有这样的k,相邻两个数之间用单个空格隔开;若没有这样的k,则输出"none"。
样例输入
30
样例输出
2 3 5 6
大数除法,要看一个数比如7是不是某数的因子,即看除7是否为0,方法为用数组储存大数的每一位,从最高位开始,若某一位的数s[i]/7==0,则将s[i]乘10加到下一位,否则将s[i]%7乘10加到下一位。
#include<bits/stdc++.h>
using namespace std;
int main()
{
string s;
int l,i,j,tag=0,temp=0;
cin>>s;//那么长的数,只能用字符输入
l=s.length();
for(i=0;i<l;i++)
s[i]=s[i]-'0';//转换为数字
for(i=2;i<=9;i++)
{
temp=0;//从上一位加下来的数,最高位temp自然是0
for(j=0;j<l;j++)
{
if(temp+s[j]>=i)temp=((temp+s[j])%i)*10;//可以整除,这取余再乘10
else temp=(s[j]+temp)*10;//不可以,直接乘10
}
if(temp==0)
{
tag=1;//标志有因子
cout<<i<<" ";
}
}
if(tag==0)cout<<"none";
}
- 14:求10000以内n的阶乘
查看 提交 统计 提问
总时间限制: 5000ms 内存限制: 655360kB
描述
求10000以内n的阶乘。
输入
只有一行输入,整数n(0<=n<=10000)。
输出
一行,即n!的值。
样例输入
100
样例输出
93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000
还是用一维数组来储存大数,并记录大数长度。那么这个数组应该开的多大呢?也就是说10000!有多少位呢?利用极限
将n=10000代入,得到e*(10000^10000)=10000 * 10000!
即e*10^40000= 10^4 * 10000!
大概得出,开一个40000大小的数组就足够了
在每次做乘法时,例如乘456,将数组结果的每一位都乘456。下一步需要从低位开始,将进位输出到高位。此时数组的长度为len,但是做乘法之后需要更新len,要怎么做呢?首先,若j的值小于len,不管怎么样都是要走一遍的,因为新数组长度至少不会小于len。当j>=len时,此时只有a[j]的值大于等于10,才需要对数组进行更新操作。
#include <bits/stdc++.h>
using namespace std;
int main()
{
int a[41000];//储存数据的数组
int n,i,j,k,len=1;
a[1]=1;
cin>>n;
for(i=2;i<=n;i++)
{
for(j=1;j<=len;j++)
a[j]*=i;//做阶乘,每次乘i
for(j=1;j<len||(j>=len&&a[j]>=10);j++)//更新数组
{
if(a[j]>=10)
{
a[j+1]+=a[j]/10;
a[j]=a[j]%10;
}
}
len=j;
}
for(i=len;i>=1;i--)
cout<<a[i];
}
- 15:阶乘和
查看 提交 统计 提问
总时间限制: 1000ms 内存限制: 65536kB
描述
用高精度计算出S=1!+2!+3!+…+n!(n≤50)
其中“!”表示阶乘,例如:5!=54321。
输入正整数N,输出计算结果S。
输入
一个正整数N。
输出
计算结果S。
样例输入
5
样例输出
153
这题思路跟上题一样,只不过要开两个数组,一个存储来计算阶乘,一个存储计算过的阶乘和。
#include <bits/stdc++.h>
using namespace std;
int main()
{
int a[40000],b[40000]={0};
int n,i,j,k,len1=1,len2=1;
a[1]=1;
b[1]=1;
cin>>n;
for(i=2;i<=n;i++)
{
for(j=1;j<=len1;j++)
a[j]*=i;
for(j=1;j<=len1;j++)
{
if(a[j]>=10)
{
a[j+1]+=a[j]/10;
a[j]=a[j]%10;
}
if(a[j+1]>0&&j==len1)len1++;
//这里采用了与上题不同的宽松数组思路,在j达到最大长度时,若高位还有数则增大len的长度
}
for(k=1;k<=max(len1,len2);k++)
b[k]+=a[k];
len2=max(len1,len2);
for(k=1;k<=len2;k++)
{
if(b[k]>=10)
{
b[k+1]+=b[k]/10;
b[k]=b[k]%10;
}
if(b[j+1]>0&&j==len2)len2++;
}
}
for(i=len2;i>=1;i--)
cout<<b[i];
}