编程基础之一维数组

  • 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!有多少位呢?利用极限lim(n→∞)
将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];
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值