题解:CF2252E Generational Triplets
易知题目条件的充要条件如下:
-
2 \times (a \operatorname{and} c) = a \oplus c -
1 \le a < c \le n
证明需要用到下面的引理(其实是常识),是容易的,不再赘述。
:::info[引理]
证明:每位单独考虑,显然有:
上式带入下式即证。
:::
对于条件
考虑数位 dp,我用
转移等具体见代码:
:::info[code]
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 65;
const int MOD = 1e9 + 7;
int ttt, W;
ll n, f[N][2][2][2][2][2];
ll solve(int w, int x, bool l1, bool l2, bool l, bool g){
ll &res = f[w][x][l1][l2][l][g];
if(res != -1) return res;
int u1 = l1 ? ((n >> w) & 1) : 1, u2 = l2 ? ((n >> w) & 1) : 1;
if(!w){
res = 0;
for(int i = 0; i <= u1; i++){
for(int j = 0; j <= u2; j++){
if(g && j < i) continue;
if(i || !l) res += ((i ^ j) == 0 && (i & j) == x);
}
}
res %= MOD;
return res;
}
res = 0;
for(int i = 0; i <= u1; i++){
for(int j = 0; j <= u2; j++){
if(g && j < i) continue;
if((i & j) != x) continue;
res = (res + solve(w - 1, (i ^ j), l1 && i == u1, l2 && j == u2, l && i == 0, g && i == j)) % MOD;
}
}
return res;
}
int main(){
ios :: sync_with_stdio(false);
cin >> ttt;
while(ttt--){
cin >> n;
memset(f, -1, sizeof(f));
W = __lg(n);
cout << solve(W, 0, 1, 1, 1, 1) << '\n';
}
return 0;
}
:::