USACO习题:Palindromic Squares
这道题的核心是考回文数字的判断。判断回文的手法基本可以分两类。
1.转换成字符串来判断,也是参考答案里的做法。(思路比较简单,这里不在熬述)
2.数学方式来判断(只能判断数字),使用mod的方法。这个方法的好处是,不要把数字转换成相应进制的表达方式然后再判断。
手法比较巧妙。
下面我来讲解下方法2.
首先我们从最简单的十进制讲起,比如有个数 123。
十进制的表示: 1*10^2 + 2*10 + 3
如何把这个数颠倒?
0*10 + 123 % 10 = 3 然后 123/10=12
3*10 + 12%10 = 32 然后 12/10 = 1
32*10 + 1%10 = 321
看出什么规律来了么?
我们再来看一下某个回文数字:12321,显而易见12321的颠倒任然是12321。
所以我们得出结论一个数字是回文当且仅当他的颠倒和原数字相等。
刚才的例子里,我们是以10进制为例子的,现在我们想想2进制的情况。
我们如何转换10进制到2进制?
12 % 2 = 0 , 12/2=6
6%2 = 0 , 6/2 = 3
3%2 = 1, 3/2 = 1
1%2 = 1
12转换好以后就是1100。发现什么了么?其实10转2产生的字符正是12的2进制数的颠倒,也就是说
使用和刚才10进制相同的方式,一样可以得到2进制的颠倒的值,然后用颠倒和原值比较即可。
或许有人会说:原来的值是10进制的,转成二进制的颠倒比较不会不一样么?
其实这里是比较绕的,无论是10进制还是2进制,他们的值本身是一样的。
也就是说用 二进制颠倒过来的数值 = 原10进制 --> 2进制 --> 颠倒 --> 利用二进制求出该数的值
换句话说不管什么进制怎么转换,其值是不变的,也就是说10进制和2进制的值的比较是合理的。
bool is_palindrome(int num,int base){
int reversed = 0,temp=num;
while(temp!=0){
reversed = reversed*base + temp%base;
temp/=base;
}
return (reversed==num);
}
如果不了解的话,多调试下代码,体会下吧。