题面
解法
比较简单的数位dp
- 表示 x xor 3x=2x x x o r 3 x = 2 x 这个方程并不会解,那么我们把小规模的解 x x 打出来看看?
- 然后我们就发现,满足这样一个条件:转换成二进制后任意相邻两个二进制位不都为1
- 对于求 [1,n] [ 1 , n ] 中有多少个满足这个条件的数直接数位dp一下就可以了
- 然后考虑如何求 [1,2n] [ 1 , 2 n ] 满足这个性质的数的个数
- 设 f[i][0] f [ i ] [ 0 ] 表示二进制下第 i i 位为且合法的数, f[i][1] f [ i ] [ 1 ] 同理
- 转移十分简单, f[i][0]=f[i−1][0]+f[i−1][1],f[i][1]=f[i−1][0] f [ i ] [ 0 ] = f [ i − 1 ] [ 0 ] + f [ i − 1 ] [ 1 ] , f [ i ] [ 1 ] = f [ i − 1 ] [ 0 ]
- 发现这个可以矩阵乘法,然后就做完了
- 时间复杂度: O(Tlogn) O ( T log n )
代码
#include <bits/stdc++.h>
#define Mod 1000000007
#define LL long long
using namespace std;
template <typename node> void chkmax(node &x, node y) {x = max(x, y);}
template <typename node> void chkmin(node &x, node y) {x = min(x, y);}
template <typename node> void read(node &x) {
x = 0; int f = 1; char c = getchar();
while (!isdigit(c)) {if (c == '-') f = -1; c = getchar();}
while (isdigit(c)) x = x * 10 + c - '0', c = getchar(); x *= f;
}
struct solve1 {
LL a[110], f[110][2][2];
LL dp(int i, int las, int l) {
if (i == 0) return 1;
if (!l && f[i][las][l] != -1) return f[i][las][l];
LL ret = 0, x = l ? a[i] : 1;
for (int j = 0; j <= x; j++) {
if (las && j) continue;
ret += dp(i - 1, j, l && j == a[i]);
}
if (!l) f[i][las][l] = ret;
return ret;
}
LL solve(LL n) {
memset(f, -1, sizeof(f));
int len = 0;
while (n) a[++len] = n % 2, n /= 2;
return dp(len, 0, 1) - 1;
}
} sol1;
struct Matrix {
int a[3][3];
void Clear() {memset(a, 0, sizeof(a));}
};
Matrix operator * (Matrix x, Matrix y) {
Matrix ret; ret.Clear();
for (int k = 1; k <= 2; k++)
for (int i = 1; i <= 2; i++)
for (int j = 1; j <= 2; j++)
ret.a[i][j] = (ret.a[i][j] + 1ll * x.a[i][k] * y.a[k][j] % Mod) % Mod;
return ret;
}
Matrix operator ^ (Matrix x, LL y) {
Matrix ret = x; y--;
while (y) {
if (y & 1) ret = ret * x;
y >>= 1, x = x * x;
}
return ret;
}
LL solve(LL n) {
Matrix tx; tx.Clear();
tx.a[1][1] = tx.a[1][2] = tx.a[2][1] = 1;
tx = tx ^ n;
Matrix ty; ty.Clear(); ty.a[1][1] = 1;
ty = tx * ty;
return (ty.a[1][1] + ty.a[2][1]) % Mod;
}
int main() {
int T; read(T);
while (T--) {
LL n; read(n);
cout << sol1.solve(n) << "\n" << solve(n) << "\n";
}
return 0;
}