【题意】
【分析】
按位异或有一个性质:若a⨁b=ca \bigoplus b=ca⨁b=c, 则a⨁c=ba \bigoplus c = ba⨁c=b。
所以说:
x⨁3x=2x⟺x⨁2x=3x⟺x⨁2x=x+2xx\bigoplus 3x=2x \Longleftrightarrow x \bigoplus 2x =3x \Longleftrightarrow x \bigoplus 2x=x+2xx⨁3x=2x⟺x⨁2x=3x⟺x⨁2x=x+2x
又有:
2x⟺x<<12x \Longleftrightarrow x<<12x⟺x<<1
所以
x⨁2x=x+2x⟺x&(x<<1)=0x \bigoplus 2x=x+2x \Longleftrightarrow x \& (x<<1)=0x⨁2x=x+2x⟺x&(x<<1)=0
即x的二进制不存在相邻的1。
于是,对于第一问,设f(i,0/1)f(i,0/1)f(i,0/1)为当前做到第iii位,前一位为0/1,然后按照题意转移即可。
然而,对于第二问,由于位数太长,所以不能用上面那个方法。
我们设g(i)=f(i,0)+f(i,1)g(i)=f(i,0)+f(i,1)g(i)=f(i,0)+f(i,1),然后对g(i)g(i)g(i)变形:
g(i)=f(i,0)+f(i,1)=f(i−1,0)+f(i−1,1)+f(i−1,0)=g(i−1)+f(i−2,0)+f(i−2,1)=g(i−1)+g(i−2)
\begin{aligned}
g(i)&=f(i,0)+f(i,1)\\&=f(i-1,0)+f(i-1,1)+f(i-1,0)\\&=g(i-1)+f(i-2,0)+f(i-2,1)\\&=g(i-1)+g(i-2)
\end{aligned}g(i)=f(i,0)+f(i,1)=f(i−1,0)+f(i−1,1)+f(i−1,0)=g(i−1)+f(i−2,0)+f(i−2,1)=g(i−1)+g(i−2)
其中:
g(1)=2,g(2)=3g(1)=2,g(2)=3g(1)=2,g(2)=3
发现这是一个斐波那契数列,g(i)g(i)g(i)为其i+2i+2i+2项,直接矩阵加速即可。
【代码】
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define ll long long
using namespace std;
const int mn = 100, mod = 1e9 + 7;
struct matrix{
ll a[3][3];
matrix operator *(const matrix b) const
{
matrix c;
memset(c.a, 0, sizeof c.a);
for(int i = 1; i <= 2; i++)
for(int j = 1; j <= 2; j++)
for(int k = 1; k <= 2; k++)
c.a[i][j] += (a[i][k] * b.a[k][j]) % mod, c.a[i][j] %= mod;
return c;
}
}ret, h;
int d[mn];
ll f[mn][2];
ll dp(int pos, int las, bool lim)
{
if(!pos)
return 1;
if(!lim && ~f[pos][las])
return f[pos][las];
int m = lim ? d[pos] : 1;
ll ans = 0;
for(int i = 0; i <= m; i++)
if(las == 1 && i == 1)
continue;
else
ans += dp(pos - 1, i, lim && i == m);
if(!lim)
f[pos][las] = ans;
return ans;
}
inline ll calc(ll n)
{
int cnt = 0;
while(n)
d[++cnt] = n & 1, n >>= 1;
return dp(cnt, -1, 1);
}
inline ll ksm(ll b)
{
while(b)
{
if(b & 1)
ret = ret * h;
h = h * h, b >>= 1;
}
memset(h.a, 0, sizeof h.a);
h.a[1][1] = 1, h = h * ret;
return h.a[1][1];
}
inline void init()
{
memset(ret.a, 0, sizeof ret.a), memset(h.a, 0, sizeof h.a);
ret.a[1][1] = ret.a[2][2] = 1, h.a[1][1] = h.a[2][1] = h.a[1][2] = 1;
}
int main()
{
int t;
ll n;
scanf("%d", &t), memset(f, -1, sizeof f);
while(t--)
{
scanf("%lld", &n), init();
printf("%lld\n%lld\n", calc(n) - 1, ksm(n + 1));
}
}