标签:
题目链接:sicily 1214
解题思路:
首先我觉得这是一道很好而且比较难的题,难度在于找规律。
题目告诉我们,n是一个很大的数(刚好在unsigned的范围内),这样的话,直接模拟是必然超时的,所以,我们需要根据题目的三条公式来推导a[n]。
这个规律我找了很久也没能找到,最后直接拿来用的,怎么想得到的我也不懂。规律如下:如果n的二进制形式满足回文序列的形式,那么a[n]=n。
得到这个规律,那么我们的题目就可以转换成找[1,n]中找到所有的数i,i满足二进制形式是回文序列。前面已经排除掉暴力模拟这个解法了,那么我们现在就只能构造了。考虑到i的二进制顶多也就是32位,回文序列的话我们可以只看16位,所以我们可以暴力枚举前16位,然后再用翻转操作求得整个回文序列,这样时间复杂度是2^16,可以接受。
之后的事情就是深搜暴力枚举啦,不再废话!
代码:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
unsigned n,tmp;
unsigned cnt,ans;
const unsigned delta=1;
unsigned getLen(unsigned num)
{
unsigned len=0;
while(num)
num>>=1,len++;
return len;
}
unsigned reverse(unsigned num)
{
unsigned res=0;
while(num) {
res=(res<<1)|(num&1);
num>>=1;
}
return res;
}
void cal(unsigned num)
{
if(num==0)
return;
unsigned len=getLen(num),res=0;
if(((num<<len)|reverse(num))<=n)
ans++;
if(((num<<len-1)|reverse(num>>1))<=n)
ans++;
}
void dfs(unsigned sum,int cnt)
{
if(cnt==0)
{
cal(sum);
return;
}
dfs(sum<<1,cnt-1);
dfs((sum<<1)+delta,cnt-1);
}
int main()
{
while(~scanf("%u",&n))
{
ans=0;
dfs(0,16);
printf("%u\n",ans);
}
return 0;
}
总结:
1、用二进制的思想考虑算法
2、多使用位运算
标签:
原文地址:http://blog.csdn.net/fuyukai/article/details/46046127