D. 崔逗逗给你信心 2014新生暑假个人排位赛04
时间限制 1000 ms
内存限制65536 KB
题目描述
崔逗逗是一个善良的学长,最喜欢为学弟学妹出水题。他给大家一个整数n,求0<=x<=n的范围内,有多少个数满足(x)^(2x)^(3x)==0 (^是异或符号)。你只要告诉他对1000000009取余的答案就好啦。
输入格式
输入有多组数据,数量在100以内,每行一个整数n(0<=n<=10^18)。
输出格式
每组数据输出一行答案。
输入样例
1
2
输出样例
2
3
首先,亦或是与一个数的二进制表示有关,转化为二进制后,由x^(2x)==3x和x+(2x)==3x知,画出图来发现对于一个数,相邻的数不能为1,设相邻的数L位的总数为f(L),不难发现,若最后一位为0,前面L-1变成了一个子问题f(L-1),若最后一位为1,倒数第二位可1可0,前面L-2变成了一个子问题f(L-2),初始化f(0)=1,f(1)=2,则转化为一个二进制数与f(L)的关系,我们可以先求出L-1的最大表示1111...1,然后从倒数第二位开始递推,若该位为1,则该位为0的前面i-1为子问题f(i-1),并记录前驱,若不满足了则跳出。
代码:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#define MOD 1000000009
using namespace std;
long long n,ans;
int bit[100],f[100],referbit[100];
int main()
{
f[0]=1;f[1]=2;
for(int i=2;i<=70;i++)f[i]=(f[i-1]+f[i-2])%MOD;
while(scanf("%lld",&n)==1)
{
if(n==0){printf("1\n");continue;}
memset(bit,0,sizeof(bit));
//memset(referbit,0,sizeof(bit));
while(n)
{
bit[0]++;
bit[bit[0]]=n%2;
n/=2;
}
int pre=1,i;ans=f[bit[0]-1];
for(i=bit[0]-1;i>=1;i--)
{
if(bit[i]==0){pre=0;continue;}
if(bit[i]==1)
{
ans=ans+f[i-1];
if(pre==1)break;
else pre=1;
}
}
if(i==0)ans=(ans+1)%MOD;
printf("%lld\n",ans%MOD);
}
return 0;
}
/*
a[0]=1
a[1]=2
a[2]=3
a[3]=3
a[4]=4
a[5]=5
a[6]=5
a[7]=5
a[8]=6
a[9]=7
a[10]=8
a[11]=8
a[12]=8
a[13]=8
a[14]=8
a[15]=8
a[16]=9
a[17]=10
a[18]=11
a[19]=11
a[20]=12
a[21]=13
a[22]=13
a[23]=13
a[24]=13
a[25]=13
a[26]=13
a[27]=13
a[28]=13
a[29]=13
a[30]=13
a[31]=13
a[32]=14
*/