版权声明:本文为博主原创文章,需转载请联系博主。 https://blog.csdn.net/ezoixx130/article/details/82595326
题意很明白,就是分别求~和~中有多少个数,满足。
题解:
首先,可以变为再变为。
考虑异或的定义为不进位的二进制加法,那么等号左边为不进位的二进制加法,右边为进位的二进制加法,所以等号成立当且仅当这两个数在二进制下作加法不进位。
也就是说和在二进制下不能有一位同时为1。
由于在二进制下意义为左移一位,所以一个数满足这个等式当且仅当它在二进制下没有相邻的两位同时为1。
那么对于第一问,我们只需要做一次数位dp,找出以下没有相邻两位同时为1的二进制数个数即可。
对于第二问,设为以下的满足条件的的个数(即在二进制下有位的的个数),那么转移方程为(这一位为1时,低一位只能为0,剩下位有种情况,这一位为0时,剩下位有种情况),显然这是斐波那契数列,用矩阵快速幂快速求得即可。
代码:
#include <bits/stdc++.h>
using namespace std;
#define mod 1000000007
int s[65];
long long f[65][2];
long long dp(int dep,int last,bool full)
{
if(!dep)return 1;
if(!full && f[dep][last])return f[dep][last];
int up=full?s[dep]:1;
long long ans=0;
for(int i=0;i<=up;++i)
if(i==0 || last==0)
ans+=dp(dep-1,i,full&&i==s[dep]);
if(!full)f[dep][last]=ans;
return ans;
}
void dp(long long n)
{
s[0]=0;
while(n)s[++s[0]]=n&1,n>>=1;
printf("%lld\n",dp(s[0],0,true)-1);
}
struct Matrix
{
long long a[3][3];
long long int *operator[](int x){return a[x];}
Matrix(){memset(a,0,sizeof(a));}
Matrix operator*(Matrix b)
{
Matrix c;
for(int i=1;i<=2;++i)
for(int j=1;j<=2;++j)
for(int k=1;k<=2;++k)
c[i][j]=(c[i][j]+a[i][k]*b[k][j]%mod)%mod;
return c;
}
};
void mul(long long n)
{
Matrix A,B;
A[1][1]=A[1][2]=B[1][2]=B[2][1]=B[2][2]=1;
while(n)
{
if(n&1)A=A*B;
B=B*B;
n>>=1;
}
printf("%lld\n",A[1][2]);
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
long long n;
scanf("%lld",&n);
dp(n);
mul(n);
}
}