sicily 1214

来源:互联网 发布:java同时定义多个变量 编辑:程序博客网 时间:2024/06/06 00:47

题目链接: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、多使用位运算

0 0
原创粉丝点击