zoukankan      html  css  js  c++  java
  • BZOJ 3329 Xorequ:数位dp + 矩阵快速幂

    传送门

    题意

    现有如下方程:$ x oplus 3x = 2x $

    其中 $ oplus $ 表示按位异或。

    共 $ T $ 组数据,每组数据给定正整数 $ n $,任务如下:

    1. 求出小于等于 $ n $ 的正整数中,有多少个数是该方程的解
    2. 求出小于等于 $ 2^n $ 的正整数中,有多少个数是该方程的解,输出 $ mod $ $ 10^9+7 $ 的值。

    $ (n leq 10^{18}, T leq 1000) $

    题解

    第一问

    方程 $ x oplus 3x = 2x $ 等价于 $ x oplus 2x = 3x $ 。

    由于 $ x + 2x = 3x $ ,并且“按位异或”相当于“不进位加法“

    所以我们可以知道,一个数 $ x $ 是该方程的解的充要条件为:$ x $ 在二进制表示下,没有两个相邻的 $ 1 $ 。

    $ f[i][0/1] $ 表示所有二进制下长度为 $ i $,且最右边一位为 $ 0/1 $ 的数中,满足没有两个相邻的 $ 1 $ 的数的个数。

    所以有:

    [f[i][0] = f[i-1][0] + f[i-1][1] ]

    [f[i][1] = f[i-1][0] ]

    边界条件为:$ f[0][0] = 1 $

    然后按位统计,算出小于等于 $ n $ 的答案:

    • 先让 $ n = n + 1 $ (因为最后算出的是小于某个数的答案,而这里要求小于等于)
    • 从高到低枚举 $ n $ 的每一个二进制位 $ a[i] $
    • 如果 $ a[i] = 1 $ ,那么 $ ans = ans + f[i][0] $ 。(此时累加的是第 $ i-1 $ 及之前位和原数匹配时的答案)
    • 如果 $ a[i] = 1 $ 且 $ a[i+1] = 1 $ ,退出循环。因为此时的前缀已经有两个 $ 1 $ 相邻,之后的答案都是不合法的。

    注意最终答案为 $ ans - 1 $ ,因为不包含 $ 0 $ 这个答案。

    复杂度 $ O(logn) $

    第二问

    $ g[i] $ 表示二进制下长度为 $ i $ ,满足没有两个相邻的 $ 1 $ 的数的个数。

    由于题目要求区间 $ [1, 2^i] $ 的答案,$ g[i] $ 表示区间 $ [0, 2^i-1] $ 的答案

    而 $ 0 $ 和 $ 2^i $ 一定都满足条件,所以相互抵消掉了。

    所以题目所求 $ ans = g[n] $

    然后考虑如何求 $ g[i] $ (分两种情况):

    • $ g[i] $ 中以 $ 0 $ 结尾的所有数,相当于在 $ g[i-1] $ 中的所有数末尾添了一个 $ 0 $
    • $ g[i] $ 中以 $ 1 $ 结尾的所有数,相当于在 $ g[i-2] $ 中的所有数末尾添了一个 $ 01 $

    所以有:

    [g[i] = g[i-1] + g[i-2] ]

    边界条件为:$ g[1] = 2, g[2] = 3 $

    然后用矩阵快速幂加速转移即可:

    [egin{bmatrix} g[i] & g[i+1] end{bmatrix} imes egin{bmatrix} 0 & 1 \ 1 & 1 end{bmatrix} = egin{bmatrix} g[i+1] & g[i+2] end{bmatrix} ]

    [egin{bmatrix} g[1] & g[2] end{bmatrix} imes egin{bmatrix} 0 & 1 \ 1 & 1 end{bmatrix}^{n-1} = egin{bmatrix} g[n] & g[n+1] end{bmatrix} ]

    AC Code

    #include <iostream>
    #include <stdio.h>
    #include <string.h>
    #define MAX_L 5
    #define MAX_B 70
    #define MOD 1000000007
    #define int long long
    
    using namespace std;
    
    struct Mat
    {
    	int n,m;
    	int v[MAX_L][MAX_L];
    	Mat(int _n,int _m) { n=_n,m=_m,memset(v,0,sizeof(v)); }
    	Mat() { memset(v,0,sizeof(v)); }
    };
    
    int n,t;
    int a[MAX_B];
    int dp[MAX_B][2];
    
    Mat get_unit(int x)
    {
    	Mat a(x,x);
    	for(int i=0;i<x;i++) a.v[i][i]=1;
    	return a;
    }
    
    Mat mul(const Mat &a,const Mat &b)
    {
    	Mat c(a.n,b.m);
    	for(int i=0;i<a.n;i++)
    	{
    		for(int j=0;j<b.m;j++)
    		{
    			for(int k=0;k<a.m;k++)
    			{
    				c.v[i][j]+=a.v[i][k]*b.v[k][j];
    				c.v[i][j]%=MOD;
    			}
    		}
    	}
    	return c;
    }
    
    Mat pow(Mat a,int k)
    {
    	Mat ans=get_unit(a.n);
    	while(k>0)
    	{
    		if(k&1) ans=mul(ans,a);
    		a=mul(a,a),k>>=1;
    	}
    	return ans;
    }
    
    int cal1()
    {
    	int t=n+1,len=0,ans=0;
    	while(t) a[++len]=(t&1),t>>=1;
    	a[len+1]=0,dp[0][0]=1;
    	for(int i=1;i<=len;i++)
    	{
    		dp[i][0]=dp[i-1][0]+dp[i-1][1];
    		dp[i][1]=dp[i-1][0];
    	}
    	for(int i=len;i>=1;i--)
    	{
    		if(a[i]) ans+=dp[i][0];
    		if(a[i+1] && a[i]) break;
    	}
    	return ans-1;
    }
    
    int cal2()
    {
    	Mat a(1,2),b(2,2);
    	a.v[0][0]=2,a.v[0][1]=3;
    	b.v[0][1]=b.v[1][0]=b.v[1][1]=1;
    	return mul(a,pow(b,n-1)).v[0][0];
    }
    
    signed main()
    {
    	scanf("%lld",&t);
    	while(t--)
    	{
    		scanf("%lld",&n);
    		printf("%lld
    ",cal1());
    		printf("%lld
    ",cal2());
    	}
    }
    
  • 相关阅读:
    some tips
    ORA00847: MEMORY_TARGET/MEMORY_MAX_TARGET and LOCK_SGA cannot be set together
    Chapter 01Overview of Oracle 9i Database Perfomrmance Tuning
    Chapter 02Diagnostic and Tuning Tools
    变量与常用符号
    Chapter 18Tuning the Operating System
    标准输入输出
    Trace files
    DBADeveloped Tools
    Chapter 03Database Configuration and IO Issues
  • 原文地址:https://www.cnblogs.com/Leohh/p/9097474.html
Copyright © 2011-2022 走看看