Solution -「校内题」Xorequ

0x00 前置芝士

数位dp考试里出现的小神题??

显然考场会选择打表找规律。

数位dp + 矩阵快速幂


0x01 题目描述

给定正整数 \(n\),现有如下方程 \(x \bigoplus 3x = 2x\),其中 \(\bigoplus\) 表示按位异或。

任务如下:

  1. 求出小于等于 \(n\) 的正整数中,有多少个数是该方程的解
  2. 求出小于等于 \(2^n\) 的正整数中,有多少个数是该方程的解,答案对 \(10^9 + 7\) 取模

0x02 分析

第一问

试证明满足 \(x \bigoplus 2 \times x = 3 \times x\)\(x\),二进制拆分数列里没有相邻的 \(1\)

条件可化为 \(x \bigoplus 2 \times x = x + 2 \times x\)

若有相邻的 \(1\),二倍后即错位相加,定会产生多余进位,得不到右边的答案,故矛盾。故原命题成立。

例:

0 0 1 1
0 1 1 0

推论:\(f(a, b)(b \in \{0, 1\})\) 表示第 \(a - 1\) 一位为 \(b\) 的数中共有多少个满足条件的数。

\(f(a, 0) = f(a - 1, 1) + f(a - 2, 0)\)\(f(a, 1) = f(a - 1, 0)\)。证明显然。

第二问

试证明小于 \(2 ^ n\) 的满足 \(x \bigoplus 2 \times x = 3 \times x\)\(x\) 的个数为斐波那契数列第 \(n\) 项。

\(g(a) = f(a, 0) + f(a, 1)\)。利用第一问结论推论,推导如下。

\(g(a) = f(a, 0) + f(a, 1)\)

\(g(a) = f(a - 1, 1) + f(a - 1, 0) + f(a - 1, 0)\)

\(g(a) = g(a - 1) + f(a - 2, 1) + f(a - 2, 0)\)

\(g(a) = g(a - 1) + g(a - 2)\)


0x04 具体实现

#include <cstdio>
#include <cstring>
using namespace std;

typedef long long LL;
const int MAXL = 105;
const int MAXN = 4;
const int mod = 1e9 + 7;
int flag[MAXL], a[MAXL];
LL dp[MAXL][MAXL][2][2];

struct Matrix {
    int n, m;
    LL mp[MAXN][MAXN];
    Matrix() { memset(mp, 0, sizeof mp); }
    Matrix operator * (const Matrix &x) const {
        Matrix ans;
        ans.n = n;
        ans.m = x.m;
        for (int i = 1; i <= ans.n; i++)
            for (int j = 1; j <= ans.m; j++)
                for (int k = 1; k <= m; k++)
                    ans.mp[i][j] = (ans.mp[i][j] + (mp[i][k] * x.mp[k][j]) % mod) % mod;
        return ans;
    }
};

Matrix Quick_pow(Matrix a, LL x) {
    Matrix ans;
    ans.n = 2;
    ans.m = 2;
    ans.mp[2][2] = 1;
    ans.mp[1][1] = 1;
    ans.mp[1][2] = 0;
    ans.mp[2][1] = 0;
    while (x) {
        if (x & 1)
            ans = ans * a;
        a = a * a;
        x >>= 1;
    }
    return ans;
}

LL dfs(int p, int last, bool k, bool limit, bool t) {
	if(p <= 0) 
		return !t && k;
	if(!limit && dp[p][last][t][k] != -1)
		return dp[p][last][t][k];
	int up = limit ? flag[p] : 1;
	LL ans = 0;
	for(int i = 0; i <= up; i++) 
		ans = (ans + dfs(p - 1, i, t || last == -1 || (k && i == 1 && last == 0) 
		|| (k && i == 0 && last == 0) || (k && i == 0 && last == 1), limit && (i == up), (t && !i)));
	if(!limit)
		dp[p][last][t][k] = ans;
	return ans;
}

LL Query(LL x) {
	int len = 0;
	while(x) {
		flag[++len] = (x & 1);
		x >>= 1;
	}
	return dfs(len, -1, true, true, true);
}

int main() {
	memset(dp, -1, sizeof dp);	
	int T;
	scanf ("%d", &T);
	while(T--) {
		LL n;
		scanf ("%lld", &n);
		printf("%lld\n", Query(n));
		Matrix A, cur, ans;
		A.n = 2, A.m = 2;
		A.mp[1][1] = 0;
		A.mp[1][2] = 1;
		A.mp[2][1] = 1;
		A.mp[2][2] = 1;
		ans = Quick_pow(A, n);
		cur.n = 1, cur.m = 2;
		cur.mp[1][1] = 1;
		cur.mp[1][2] = 1;
		ans = cur * ans;
		printf("%lld\n", ans.mp[1][2] % mod);
	}
	return 0;
}
posted @ 2021-01-09 12:47  STrAduts  阅读(94)  评论(0编辑  收藏  举报