模拟问题与高精度问题思考

高精度问题

在面对一些问题时,可能遇到数据值很大,大到到long long类型仍然无法存储的数据,因此我们需要利用数组储存数据来模拟位数非常多的整数。

利用数组储存数据时,一般采用翻转储存,即将低位(如个位、十位)存储在a[0]、a[1]

例如储存一个大数:

#include<bits/stdc++.h>
#define num 1010
using namespace std;
int a[num];
int main()
{	
	string s;
	cin >> s;
	for(int i=s.length()-1,j=1;i>=0;i--,j++)//位数由低到高存储从数组的首位开始
	  a[j]=s[i]-'0';
	  for(int i=s.length();i>0;i--)//先输出高位
	  cout<<a[i];
	  cout<<endl;

	return 0;
}

这就将一个最高1010位的大数存储在了一个数组中。

对于利用数组存储的数据,不可避免的涉及到数据的加和与乘积。例如我们在上述代码存储高精度数据的基础上实现两个高精度数的相乘,则有以下思考与运算过程:

 这里用了2146*1735的乘法举例,我们需要考虑乘数之后的进位问题,我们可以只考虑a*b运算之后各个位最终的数值再进行进位。

代码:

#include<bits/stdc++.h>
#define num 1010
using namespace std;
int a[num],b[num],c[num];
int main()
{	
	string s,w;
	int la,lb;
	cin >> s >>w;
	la=s.length();
	lb=w.length();
	for(int i=s.length()-1,j=0;i>=0;i--,j++)//高精度存储s
	  a[j]=s[i]-'0';
	for(int i=w.length()-1,j=0;i>=0;i--,j++)//高精度存储w
	  b[j]=w[i]-'0';
	for(int m=0;m<la;m++)//利用二重循环进行模拟乘法到 a*b(总) 部
	    for(int n=0;n<lb;n++)
		   c[m+n]+=a[m]*b[n];
	
	int lmax=la+lb;//lmax为数乘运算所能达到的最高位
	for(int p=0;p<=lmax;p++)//模拟进位
	  {
		  c[p+1]+=c[p]/10;
		  c[p]%=10;
	  }
	while(!c[lmax])//去掉高位为零的位
	      lmax--;
    for(int i=lmax;i>=0;i--)
	   cout<<c[i];
	
	cout<<endl;


	return 0;
}

运算 2146*1735 的值

Last login: Thu Mar 17 22:48:13 on ttys001

2146     
1735                 
3723310
i@HUAWEI-MateBook-X-Pro ~ % 

************************************

对于模拟问题,大部分顺应题目思路,按照题目顺序写出答案,但是仍然需要注意细节问题,题目中的每一句话都很关键,要认真审题。

 例 :
玩具谜题(洛谷 P1563,NOIP 2016 提高组)  n(n<100000)名同学依次逆时针方向围成一个圈,有些同学面向圈内,有些面向圈外。第一个同学手里有礼物。从这名同学开始进行m(m<100000)次传递。拥有礼物的同学将礼物传递给左手/右手边的第s(s<n)个人。已知每名同学的姓名(长度不超过 10 的宇符串)和朝向(0 表示朝圈内,1表示朝圈外),以及每次传递的方向(0 表示往这名同学的左边,1表示往右边)和传过的同学人数,求最后礼物在谁手上,输出姓名。

分析:该题目需要设置的数据范围很大,需要谨慎使用多重循环。不妨假设第一位同学为0号,0号同学面朝内时,向右手传礼物记为正,向左手传礼物记为负,此时如果0号同学向左传就会出现(0-2)=-2号同学拿到礼物的情况,得到的礼物不属于0~(n-1)的范围内,显然不符合现实情况,因此我们需要再加上或减去n,使其符合情况。并且可通过取余达到目的。

#include <iostream>
#include <string>

using namespace std;
const int NUM=1e6+10;
struct stu
{
    int face;
    string name;
}a[NUM];
int n,m,i,j;
int main()
{
    cin>>n>>m;//输入人数与传递次数
    for(int b=0;b<n;b++)
    {
        cin>>a[b].face>>a[b].name;
    }
    int seat=0;//代表此时礼物的位置
    for(int b=0;b<m;b++)
    {
        cin>>i>>j ; //i为传递方向0为左 1为右,j为传递人数
        if(a[b].face==0&&i==0)
        seat=(seat-j+n)%n;
        else if(a[b].face==0&&i==1)
        seat=(seat+j)%n;
        else if(a[b].face==1&&i==0)
        seat=(seat+j)%n;
        else if(a[b].face==1&&i==1)
        seat=(seat-j+n)%n;
    }
     cout<<a[seat].name<<endl;
    return 0;
}

代码实现问题穷举了四种可能出现的情况

调试结果

Last login: Mon Mar 14 19:29:29 on ttys002

3 2
0 wang 0 zhang 0 zhao
0 2
0 1
wang
i@HUAWEI-MateBook-X-Pro ~ % 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值