BZOJ3329 - Xorequ(数位dp,矩阵加速)

题目

  1. 求出小于等于n的正整数中,多少数是\(x \oplus 3x = 2x\)的解。
  2. 求出小于等于\(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;
    }
}
posted @ 2020-08-20 21:34  limil  阅读(75)  评论(0编辑  收藏  举报