【题解】【高精度】—— [NOIP1999 普及组] 回文数

[NOIP1999 普及组] 回文数

戳我查看题目(洛谷)

题目描述

若一个数(首位不为零)从左向右读与从右向左读都一样,我们就将其称之为回文数。

例如:给定一个十进制数 56 56 56,将 56 56 56 65 65 65(即把 56 56 56 从右向左读),得到 121 121 121 是一个回文数。

又如:对于十进制数 87 87 87

STEP1: 87 + 78 = 165 87+78=165 87+78=165
STEP2: 165 + 561 = 726 165+561=726 165+561=726
STEP3: 726 + 627 = 1353 726+627=1353 726+627=1353
STEP4: 1353 + 3531 = 4884 1353+3531=4884 1353+3531=4884

在这里的一步是指进行了一次 N N N 进制的加法,上例最少用了 4 4 4 步得到回文数 4884 4884 4884

写一个程序,给定一个 N N N 2 ≤ N ≤ 10 2 \le N \le 10 2N10 N = 16 N=16 N=16)进制数 M M M 100 100 100 位之内),求最少经过几步可以得到回文数。如果在 30 30 30 步以内(包含 30 30 30 步)不可能得到回文数,则输出 Impossible!

输入格式

两行,分别是 N N N M M M

输出格式

如果能在 30 30 30 步以内得到回文数,输出格式形如 STEP=ans,其中 ans \text{ans} ans 为最少得到回文数的步数。

否则输出 Impossible!

输入输出样例

输入 #1

10
87

输出 #1

STEP=4

1.题意解析

    首先,我们还时间这道题分成几个模块。

1.基础高精度结构体分装
2.将一个高精度整数反转
3.判断一个高精度整数是否是回文数


1.基础高精度结构体分装

    在我的文章高精度算法解析和高精度赛场用模板中已经分装了一个大整数结构体。这里就不再赘述。

    我们主要要解决的是进制问题。根据n进制的特性:逢n进1,我们的展开函数就可以这样写。

void flatten(int L)//展开,根据n进制数每逢n进1的规则展开 
{
	len=L;
	for(int i=1;i<=len;i++)
		a[i+1]+=a[i]/n,a[i]%=n;
	while(!a[len])
		len--;
}

    然后是输入一个数并将它储存到高精度数里面。首先定义一个binary_num_to_ten函数。用来将每个字符转换为数字。

int binary_num_to_ten(char num)//将字母映射成数字的函数 
{
	return num>='0'&&num<='9'?num-'0':num-'A'+10; 
}

    我们先将输入的数字暂时存到字符串里面。然后利用上面定义的binary_num_to_ten函数,一位一位的存储。

    这里有个小技巧:我们不需要将字符存储起来,而是将其对应的数字存储起来,这样方便编写代码。比如F我们就储存成15

void get_num()//读取一个n进制数并储存的函数 
{
	string str;
	cin>>str;
	len=str.length();
	for(int i=str.length()-1;i>=0;i--)//遍历字符串 
		a[len-i]=binary_num_to_ten(str[i]);//映射并储存 
}

2.将一个高精度整数反转

    这个很简单,只需要将一个高精度整数逐位翻转就行了。

bigint reverse(bigint num)//翻转一个高精度整数 
{
	bigint ans;
	ans.len=num.len;
	for(int i=1;i<=num.len;i++)
	    ans[i]=num[num.len-i+1];
	return ans;
}

3.判断一个高精度整数是否是回文数

    这个也很简单,只需要判断这个数翻转过来是否跟原数相等就行了。唯一麻烦的就是还需要重载一下==

friend bool operator==(bigint a,bigint b)//判断两个数是否相等 
{
	if(a.len!=b.len)return 0;
	for(int i=1;i<=a.len;i++)
		if(a[i]!=b[i])
		    return 0;
	return 1;
}

bool is_palindrom(bigint num)//判断一个高精度整数是否是回文数 
{
	return reverse(num)==num;
}

2.AC代码

#include<bits/stdc++.h>
using namespace std;
int n,step;
int binary_num_to_ten(char num)//将字母映射成数字的函数 
{
	return num>='0'&&num<='9'?num-'0':num-'A'+10; 
}
struct bigint
{
	int a[110],len;
	bigint(int x=0)
	{
		memset(a,0,sizeof(a));
		if(x==0)
		{
			len=1;
			return;
		}
		for(len=1;x;len++)
		    a[len]=x%10,x/=10;
		len--;
	}
	int &operator[](int x)
	{
		return a[x];
	}
	void get_num()//读取一个n进制数并储存的函数 
	{
		string str;
		cin>>str;
		len=str.length();
		for(int i=str.length()-1;i>=0;i--)//遍历字符串 
		    a[len-i]=binary_num_to_ten(str[i]);//映射并储存 
	}
	friend void print(bigint x)//仅供调试时使用 
	{
		for(int i=x.len;i>=1;i--)
		    cout<<x[i];
	}
	void flatten(int L)//展开,根据n进制数每逢n进1的规则展开 
	{
		len=L;
		for(int i=1;i<=len;i++)
		    a[i+1]+=a[i]/n,a[i]%=n;
		while(!a[len])
		    len--;
	}
	friend bigint operator+(bigint a,bigint b)
	{
		bigint c;
		int lena=a.len,lenb=b.len;
		for(int i=1;i<=max(lena,lenb);i++)
		    c[i]+=a[i]+b[i];
		c.flatten(lena+lenb);
		return c;
	}
	friend bool operator==(bigint a,bigint b)//判断两个数是否相等 
    {
	    if(a.len!=b.len)return 0;
	    for(int i=1;i<=a.len;i++)
		    if(a[i]!=b[i])
		        return 0;
	    return 1;
    }
};
bigint reverse(bigint num)//翻转一个高精度整数 
{
	bigint ans;
	ans.len=num.len;
	for(int i=1;i<=num.len;i++)
	    ans[i]=num[num.len-i+1];
	return ans;
}
bool is_palindrom(bigint num)//判断一个高精度整数是否是回文数 
{
	return reverse(num)==num;
}
int main()
{
	bigint m;
	cin>>n;
	m.get_num();
	for(step=1;step<=30&&!is_palindrom(m);step++)//重复执行这个操作 
	{
		m=m+reverse(m);
		if(is_palindrom(m))//变成回文数了就跳出 
		    break;
	}
	if(step<=30&&is_palindrom(m))//满足条件,输出步数 
	    cout<<"STEP="<<step;
	else
	    cout<<"Impossible!";
	return 0;
}

喜欢就订阅此专辑吧!

【蓝胖子编程教育简介】
蓝胖子编程教育,是一家面向青少年的编程教育平台。平台为全国青少年提供最专业的编程教育服务,包括提供最新最详细的编程相关资讯、最专业的竞赛指导、最合理的课程规划等。本平台利用趣味性和互动性强的教学方式,旨在激发孩子们对编程的兴趣,培养他们的逻辑思维能力和创造力,让孩子们在轻松愉快的氛围中掌握编程知识,为未来科技人才的培养奠定坚实基础。

欢迎扫码关注蓝胖子编程教育
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蓝胖子教编程

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值