牛客的回文数

学习笔记,仅供参考,希望各位大佬纠错。

链接1:

https://ac.nowcoder.com/acm/contest/20960/1008

题意1:

给出 10 个数码的出现次数,0 到 9 的出现次数均小于 10,找到一个由这些数码组成的最小的数,该数是回文数且不能有前导 0。

代码1:

#include 
#include 
using namespace std;
int main(void)
{
	int x;
	string ans, mid;
	for (int i = 0; i <= 9; i++)
	{
		cin >> x;
		if (x & 1) mid += ('0' + i);
		for (int j = 1; j <= x / 2; j++) ans += ('0' + i);
	}
	if (mid.size() > 1) puts("-1");
	else
	{
		int index = 0;
		while (index < ans.size() && ans[index] == '0') index++;
		if (index == ans.size() && index != 0) puts("-1");
		else
		{
			swap(ans[index], ans[0]);
			cout << ans << mid;
			reverse(ans.begin(), ans.end());
			cout << ans << endl;
		}
	}
	return 0;
}

解释1:

回文数的数位可以是奇数,mid 就是用来存储中间位的数,所以 mid 的长度不能大于 1 ,否则就不能构成回文数。因此先判断 x 是否为奇数,是奇数就从中拿出一个存在 mid 中。

x & 1:& 是按位与,该式可用来判断 x 是否为奇数,即与 1 进行与运算,如果 x 二进制最后一位是 1 ,那么结果为 1 ,否则为 0 。

mid += ( '0' + i ):字符型与整数相加,等于字符 0 的 ASCII 码加上 i 后的 ASCII值所对应的字符。

ans 是用来存储回文数对称的一半,故循环时 x 要取一半,因此后面程序有输出 mid 中间位后再输出倒置的 ans。

ans += ( '0' + i ):字符相加运算是把字符连接起来。

ans 中会有前导 0,此时分两种情况讨论,一是 ans 中全是 0,即 index == ans.size ( ) 且 index != 0 时,是没有回文数的;二是 ans 中不全为 0,那么就要进行换位,将最后一个 0 后面的数( ans [ index ])与首位(ans [ 0 ])交换。

若ans 中没有前导 0,那么直接进入 else 语句,符合的条件是 index != ans.size () 并且 index == 0,正因如此,所以 else 前面的 if 语句条件要再设置一个条件 index != 0,因 index 为 0,swap 函数执行无意义。

总结1:

        代码是借鉴别人的代码改了一些些,第一次看题目,没有一点思绪,无从下手,后面看别人代码时也看不太懂,然后通过问老师、调试、上网找资料才略懂一点,耗时是比较长的。但是,其中暴露出很多问题,是值得自己深思和改正的。最后想说,算法真不好学,需要花时间,有足够的耐心,得迎难而上。一道题可能要花好长时间写出代码,又要花好长时间调试代码,最后真正解决完这道题的时间可能花了很久很久,期间心情都被整 emo 了。但这也是学习的过程,对于我们小白来说,就是慢慢来,一步步进阶,脚踏实地。" 既然选择了远方,便只顾风雨兼程 ",一起共勉。

链接2:

https://ac.nowcoder.com/acm/contest/20960/1009

题意2:
一个N( 2 <= N <= 10 或 N = 16)进制数 M(100位之内),不断地将它与它的反序数(即将整数的数字倒过来形成的整数)相加,求最少经过几步可以得到回文数,步数要小于 30,否则就输出 " Impossible! "。

代码2:

#include
using namespace std;
int main()
{
	int n;
    string a;
    cin >> n >> a;
    int l = a.size();
    long long res = 0;
    for(int i = 0;i < l;i ++)
        if(a[i] <= '9')
			res = res*n + a[i] - '0';
        else res = res*n + a[i] - 'A' + 10;
    bool f = 0;
    for(int i = 0;i < 31;i ++){
        long long k = res;
        long long d = 0;
        while(k){
            d = d*n + k%n;
            k /= n;
        }
        if(d == res){
            f = 1;
            cout << "STEP=" << i << endl;
            break;
        }
        res += d;
    }
    if(!f)
		cout << "Impossible!" << endl;
	return 0;
}

解释2:

将 n 进制数转换成10进制数,以下部分代码可实现该转换:

for(int i = 0;i < l;i ++){
        if(a[i] <= '9')
			res = res*n + a[i] - '0';
        else res = res*n + a[i] - 'A' + 10;
}

将该数先以字符型表示,从它的首位开始取,拿 9 进制下的 87 为例有:res = ( 8 * 9 + 7 ) * 9^0 = = 79,即有九进制数 87 的十进制数为 79。 

将 10 进制下的数转换成 n 进制下的反序数,输出的数是十进制的,由以下部分代码实现:

 while(k){
            d = d*n + k%n;
            k /= n;
        }

九进制数 87 的反序数是 78,其用十进制表示为 7*9 + 8 = 71,将 k = 79 代入得 d = 71,又如:

牛客的回文数_第1张图片

要顺利通过该题,res 的数据类型还得定为 long long。 

总结2:

        就这个代码,我硬是冥思苦想都不得其解,卡住一处语句上了,可能就是菜的缘故。不过呢,还是得给自己点个赞的,格物致知精神可嘉。就从上面的那个代码中,仅靠自己的理解,会收获一些新知识,不过最后完全理解还是得请大佬赐教,由此又收获了更多的知识。所以说有时还是得不懂就问,靠别人来指点迷津,而不是自己死磕,有时候不划算,耗时还毁好心情,人都给整  emo 了。算法路虽艰辛,但贵在坚持,所以,hold on!一起共勉。

你可能感兴趣的:(算法)