题解:UVA12050 Palindrome Numbers

双倍经验:ABC363D

思路

打表

nn 对应的答案
11 00
22 11
33 22
44 33
55 44
66 55
77 66
88 77
99 88
1010 99
1111 1111
1212 2222
1313 3333
1414 4444
1515 5555
1616 6666
1717 7777
1818 8888
1919 9999
2020 101101
2121 111111
2222 121121
3030 202202
3131 212212
100100 909909
101101 919919
110110 10011001
111111 11111111
112112 12211221
113113 13311331
200200 1000110001
10001000 9000990009
11001100 100001100001

不难发现,每一次答案多一位,nn 的最高两位要么是 2020,要么是 1111,并且答案是奇数位的时候 nn 最高两位是 2020,是偶数位的时候 nn 最高两位是 1111

然后我们就可以依此写出来一个打表程序。

观察最后一组样例发现有 3535 位,因此打表到 3535 位即可。

#include<bits/stdc++.h>
using namespace std;
int main(){
	cout<<"1,";
	for(int i=2;i<=35;i++){
		if(i%2==1){
			cout<<"2";
			for(int j=1;j<=i/2;j++)cout<<'0';
			cout<<',';
		}
		else {
			cout<<"11";
			for(int j=1;j<i/2;j++)cout<<'0';
			cout<<',';
		}
		if(i%4==0)cout<<endl;
	}
	return 0;
}

注意到一位数包括 00,因此特殊处理。

打表出来的数组是:

long long wei[45]= {0,1,11,20,110,
                    200,1100,2000,11000,
                    20000,110000,200000,1100000,
                    2000000,11000000,20000000,110000000,
                    200000000,1100000000,2000000000,11000000000,
                    20000000000,110000000000,200000000000,1100000000000,
                    2000000000000,11000000000000,20000000000000,110000000000000,
                    200000000000000,1100000000000000,2000000000000000,11000000000000000,
                    20000000000000000,110000000000000000,200000000000000000,1000000000000000001};

我们在这个序列中找到第一个大于等于 nn 的数,就可以确定答案的位数。

然后我们对奇数位和偶数位分开处理。

偶数位

不难发现答案为偶数位的 nn 取值范围为 [1.1×10m,2×10m)[1.1\times 10^m,2\times 10^m)(其中 m1m\ge 1)。

所以答案为偶数位的 nn 最高位都是 11

所以我们把 nn 的最高位去掉得到 pp,然后把 pp 翻转之后拼在后面,根据上面的打表这其实就是答案。

void dfs2(int now) {
	if(now>q/2+1)return;
	cout<<n10[now];
	dfs2(now+1);
	cout<<n10[now];
}

奇数位

奇数位的处理相对麻烦一点。

首先先看答案的最高位(最低位),其实就是 nn 的最高位减 11(如果 nn 最高位是 11,答案的最高位是 99)。

然后除掉 nn 的最高位(如果最高位是 11 则把最高两位一起去掉)得到 qq,把 qq 翻转过来拼到后面,根据打表,加上最高位和最低位就是答案了。

void dfs1(int now) {
	if(n10[1]==1&&n10[2]==0&&now==1) {//因为对最高位是 1 的情况过于麻烦,我特判了一下
		bool f=1;
		for(int i=3; i<=cnt; i++) {
			if(n10[i]!=0)f=0;
		}
		if(f) {
			cout<<9;
			for(int i=2; i<q; i++)cout<<0;
			cout<<9;
			return;
		}
		else{
			cout<<9;
			q++;
			dfs1(3);
			cout<<9;
			return;
		}
	}
	int g=0;
	if(now==q/2+1) {
		cout<<n10[now];
		return;
	}
	if(now==1) {
		cout<<n10[now]-1;
	} else cout<<n10[now];
	dfs1(now+g+1);
	if(now==1) {
		cout<<n10[now]-1;
	} else cout<<n10[now];
}

完整代码

#include<bits/stdc++.h>
using namespace std;
long long wei[45]= {0,1,11,20,110,
                    200,1100,2000,11000,
                    20000,110000,200000,1100000,
                    2000000,11000000,20000000,110000000,
                    200000000,1100000000,2000000000,11000000000,
                    20000000000,110000000000,200000000000,1100000000000,
                    2000000000000,11000000000000,20000000000000,110000000000000,
                    200000000000000,1100000000000000,2000000000000000,11000000000000000,
                    20000000000000000,110000000000000000,200000000000000000,1000000000000000001

                   };
//设置最后一个数的意义:防止对于极大的数据找不到要求的位数
long long n;
int flag,n10[25],cnt,q;
void dfs1(int now) {
	if(n10[1]==1&&n10[2]==0&&now==1) {
		bool f=1;
		for(int i=3; i<=cnt; i++) {
			if(n10[i]!=0)f=0;
		}
		if(f) {
			cout<<9;
			for(int i=2; i<q; i++)cout<<0;
			cout<<9;
			return;
		}
		else{
			cout<<9;
			q++;
			dfs1(3);
			cout<<9;
			return;
		}
	}
	int g=0;
	if(now==q/2+1) {
		cout<<n10[now];
		return;
	}
	if(now==1) {
		cout<<n10[now]-1;
	} else cout<<n10[now];
	dfs1(now+g+1);
	if(now==1) {
		cout<<n10[now]-1;
	} else cout<<n10[now];
}
void dfs2(int now) {
	if(now>q/2+1)return;
	cout<<n10[now];
	dfs2(now+1);
	cout<<n10[now];
}
int ans[15]= {0,0,1,2,3,4,5,6,7,8,9};
int main() {
	cin>>n;
	if(n<=10) {
		cout<<ans[n];
		return 0;
	}
	for(int i=1; i<=36; i++) {
		if(wei[i]>n) {
//问题:当 n 取极大值时,如果只是判断 35 位,可能找不到 q 的值
			flag=(i-1)%2;
			q=i-1;
			break;
		}
	}
	while(n) {
		n10[++cnt]=n%10;
		n/=10;
	}
	for(int i=1; i<=cnt/2; i++) {
		swap(n10[i],n10[cnt-i+1]);
	}
	if(flag)dfs1(1);
	else dfs2(2);
	return 0;
}

为什么可以用递归实现?

因为不难发现一个奇位回文数都是在之前产生的一个奇位回文数两边加上一个相同的数,偶位回文数同理。

这样,我们可以递归把 nn 的最高位去掉。因为去掉的是最高位,所以我先把 nn 的十进制各位分离,然后通过数组下标实现去除最高位。

posted @   Weslie_qwq  阅读(1)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示