题解:UVA12050 Palindrome Numbers
双倍经验:ABC363D。
思路
打表
| 对应的答案 | |
|---|---|
不难发现,每一次答案多一位, 的最高两位要么是 ,要么是 ,并且答案是奇数位的时候 最高两位是 ,是偶数位的时候 最高两位是 。
然后我们就可以依此写出来一个打表程序。
观察最后一组样例发现有 位,因此打表到 位即可。
#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;
}
注意到一位数包括 ,因此特殊处理。
打表出来的数组是:
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};
我们在这个序列中找到第一个大于等于 的数,就可以确定答案的位数。
然后我们对奇数位和偶数位分开处理。
偶数位
不难发现答案为偶数位的 取值范围为 (其中 )。
所以答案为偶数位的 最高位都是 。
所以我们把 的最高位去掉得到 ,然后把 翻转之后拼在后面,根据上面的打表这其实就是答案。
void dfs2(int now) {
if(now>q/2+1)return;
cout<<n10[now];
dfs2(now+1);
cout<<n10[now];
}
奇数位
奇数位的处理相对麻烦一点。
首先先看答案的最高位(最低位),其实就是 的最高位减 (如果 最高位是 ,答案的最高位是 )。
然后除掉 的最高位(如果最高位是 则把最高两位一起去掉)得到 ,把 翻转过来拼到后面,根据打表,加上最高位和最低位就是答案了。
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;
}
为什么可以用递归实现?
因为不难发现一个奇位回文数都是在之前产生的一个奇位回文数两边加上一个相同的数,偶位回文数同理。
这样,我们可以递归把 的最高位去掉。因为去掉的是最高位,所以我先把 的十进制各位分离,然后通过数组下标实现去除最高位。

浙公网安备 33010602011771号