BZOJ3329 - Xorequ(数位dp,矩阵加速)
题目
- 求出小于等于n的正整数中,多少数是\(x \oplus 3x = 2x\)的解。
- 求出小于等于\(2^n\)的正整数中,多少数是\(x \oplus 3x = 2x\)的解,模1e9+7。
题解
观察方程的解的性质,可以化成\(x \oplus 2x = 3x = (x + 2x)\)。异或有称作无进位的加,所以二进制表示下,x左移一位后不能和原来的x有相同的1,即x的没有连续的1。
第一问用普通数位dp,第二问列出dp式可以发现就是Fibonacci数列。
第二问一开始我脑抽搞错成求第\(2^n\)项,本想用通项+降幂,结果发现5在模1e9+7下不是二次剩余,即没有可以替代根号5的数。后来才发现n个二进制位,求第n项即可,这用矩阵加速就好了。
#include <bits/stdc++.h>
#define endl '\n'
#define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define FILE freopen(".//data_generator//in.txt","r",stdin),freopen("res.txt","w",stdout)
#define FI freopen(".//data_generator//in.txt","r",stdin)
#define FO freopen("res.txt","w",stdout)
#define pb push_back
#define mp make_pair
#define seteps(N) fixed << setprecision(N)
typedef long long ll;
using namespace std;
/*-----------------------------------------------------------------*/
ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
#define INF 0x3f3f3f3f
const int N = 3e5 + 10;
const int M = 1e9 + 7;
const int M1 = M - 1;
const int M2 = 533333328;
const double eps = 1e-5;
int di[N];
ll n;
ll f[N][2];
struct Mat {
ll arr[2][2];
Mat() {
memset(arr, 0, sizeof arr);
arr[0][0] = arr[1][1] = 1;
}
Mat operator * (const Mat& rhs) const {
Mat tmp;
for(int i = 0; i < 2; i++) {
for(int j = 0; j < 2; j++) {
tmp.arr[i][j] = 0;
for(int k = 0; k < 2; k++) {
tmp.arr[i][j] += arr[i][k] * rhs.arr[k][j] % M;
tmp.arr[i][j] %= M;
}
}
}
return tmp;
}
};
Mat mqpow(Mat a, ll b) {
Mat res;
while(b) {
if(b & 1) res = res * a;
a = a * a;
b = b >> 1;
}
return res;
}
inline ll qpow(ll a, ll b, ll m) {
ll res = 1;
while(b) {
if(b & 1) res = (a * res) % m;
a = (a * a) % m;
b = b >> 1;
}
return res;
}
ll dfs(int p, bool st, bool lmt) {
if(!p) {
return 1;
}
if(!lmt && f[p][st] >= 0) return f[p][st];
ll res = 0;
int maxx = lmt ? di[p] : 1;
for(int i = 0; i <= maxx; i++) {
if(st && i) continue;
res += dfs(p - 1, i == 1, lmt && i == maxx);
}
if(!lmt) f[p][st] = res;
return res;
}
ll solve(ll x) {
int tot = 0;
while(x) {
di[++tot] = (x & 1);
x >>= 1;
}
return dfs(tot, 0, 1);
}
int main() {
IOS;
memset(f, -1, sizeof f);
int t;
cin >> t;
while(t--) {
ll n;
cin >> n;
cout << solve(n) - 1 << endl;
Mat ans;
ans.arr[0][1] = 1;
ans.arr[1][0] = 1;
ans.arr[1][1] = 0;
ans = mqpow(ans, n);
cout << ((ans.arr[0][0] + ans.arr[0][1]) % M + M) % M << endl;
}
}