zoukankan      html  css  js  c++  java
  • Xorequ 题解

    0x00 前置芝士

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

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

    数位dp + 矩阵快速幂


    0x01 题目描述

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

    任务如下:

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

    0x02 分析

    第一问

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

    条件可化为 (x igoplus 2 imes x = x + 2 imes 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 igoplus 2 imes x = 3 imes 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
    ", 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
    ", ans.mp[1][2] % mod);
    	}
    	return 0;
    }
    
  • 相关阅读:
    SJTU T4143 推箱子
    Markdown基本语法
    命令行的操作——cd
    C++ ------- 类和对象
    数据结构------栈和队列
    MySQL------ 子查询
    MySQL------ SQL99语法
    C++------内存分区模型
    第三章------数据链路层
    MySQL------ SQL92语法
  • 原文地址:https://www.cnblogs.com/Chain-Forward-Star/p/14254620.html
Copyright © 2011-2022 走看看