【题解】【BZOJ3329】Xorequ

版权声明:本文为博主原创文章,需转载请联系博主。 https://blog.csdn.net/ezoixx130/article/details/82595326

题意很明白,就是分别求1~n1~2^n中有多少个数x,满足x \oplus 3x = 2x

题解:

首先,x \oplus 3x = 2x可以变为x \oplus 2x = 3x再变为x \oplus 2x = x + 2x

考虑异或的定义为不进位的二进制加法,那么等号左边为不进位的二进制加法,右边为进位的二进制加法,所以等号成立当且仅当这两个数在二进制下作加法不进位。

也就是说x2x在二进制下不能有一位同时为1。

由于2x在二进制下意义为x左移一位,所以一个数x满足这个等式当且仅当它在二进制下没有相邻的两位同时为1。

那么对于第一问,我们只需要做一次数位dp,找出n以下没有相邻两位同时为1的二进制数个数即可。

对于第二问,设f[i]2^i以下的满足条件的x的个数(即在二进制下有i位的x的个数),那么转移方程为f[i]=f[i-1]+f[i-2](这一位为1时,低一位只能为0,剩下i-2位有f[i-2]种情况,这一位为0时,剩下i-1位有f[i-1]种情况),显然这是斐波那契数列,用矩阵快速幂快速求得即可。

代码:

#include <bits/stdc++.h>
using namespace std;

#define mod 1000000007

int s[65];
long long f[65][2];

long long dp(int dep,int last,bool full)
{
	if(!dep)return 1;
	if(!full && f[dep][last])return f[dep][last];
	int up=full?s[dep]:1;
	long long ans=0;
	for(int i=0;i<=up;++i)
		if(i==0 || last==0)
			ans+=dp(dep-1,i,full&&i==s[dep]);
	if(!full)f[dep][last]=ans;
	return ans;
}

void dp(long long n)
{
	s[0]=0;
	while(n)s[++s[0]]=n&1,n>>=1;
	printf("%lld\n",dp(s[0],0,true)-1);
}

struct Matrix
{
	long long a[3][3];
	long long int *operator[](int x){return a[x];}
	Matrix(){memset(a,0,sizeof(a));}
	Matrix operator*(Matrix b)
	{
		Matrix c;
		for(int i=1;i<=2;++i)
			for(int j=1;j<=2;++j)
				for(int k=1;k<=2;++k)
					c[i][j]=(c[i][j]+a[i][k]*b[k][j]%mod)%mod;
		return c;
	}
};

void mul(long long n)
{
	Matrix A,B;
	A[1][1]=A[1][2]=B[1][2]=B[2][1]=B[2][2]=1;
	while(n)
	{
		if(n&1)A=A*B;
		B=B*B;
		n>>=1;
	}
	printf("%lld\n",A[1][2]);
}

int main()
{
	int T;
	scanf("%d",&T);
	while(T--)
	{
		long long n;
		scanf("%lld",&n);
		dp(n);
		mul(n);
	}
}

猜你喜欢

转载自blog.csdn.net/ezoixx130/article/details/82595326