题意
大致思路:通过观察、打表、推式子……最后可知
p[i]=i对应的二进制相邻两位不同的值
p
[
i
]
=
i
对
应
的
二
进
制
相
邻
两
位
不
同
的
值
q[i]=i对应的二进制相邻两位相同的值
q
[
i
]
=
i
对
应
的
二
进
制
相
邻
两
位
相
同
的
值
a[i]=p[i]+q[i]
a
[
i
]
=
p
[
i
]
+
q
[
i
]
这时候就可以用数位DP去解这道题了。
开状态的时候,第一位pos表示当前处理到第几位,state表示当前这个状态下a[i]的值,还有一个pre,表示前一位是什么数。
#include<bits/stdc++.h>
using namespace std;
const int mod = 1e9 + 7;
int t, num[66], len;
typedef long long ll;
ll dp[66][133][3], n;
ll dfs(int pos, int state, int limit, int pre) {
if (pos == -1) return abs(state - 66);
if (dp[pos][state][pre] != -1 && !limit) return dp[pos][state][pre];
int up = limit ? num[pos] : 1;
ll cnt = 0;
for (int i = 0; i <= up; i++) {
if (pre == 2) {
if (i) cnt += dfs(pos - 1, state, limit && i == num[pos], 1);
else cnt += dfs(pos - 1, state, limit && i == num[pos], pre);
if (cnt > mod) cnt -= mod;
if (cnt < 0) cnt += mod;
}
else {
cnt += dfs(pos - 1, state + ((i == pre) ? 1 : -1), limit && i == num[pos], i);
if (cnt > mod) cnt -= mod;
if (cnt < 0) cnt += mod;
}
}
if (!limit) dp[pos][state][pre] = cnt;
return cnt;
}
ll solve(ll x) {
len = 0;
while (x) {
num[len++] = x & 1;
x >>= 1;
}
return dfs(len - 1, 66, 1, 2);
}
int main() {
memset(dp, -1, sizeof dp);
scanf("%d", &t);
while (t--) {
scanf("%lld", &n);
printf("%lld\n", solve(n));
}
}