bzoj 3329 - xorequ

Description

求方程x xor 3x=2x
①在n以内的解数
②在\(2^n\)以内的解数
\(n\le 2^{63}\)

Analysis

转化成x xor (x<<1)=x + (x<<1)
即x & (x<<1)=0,没有相邻的1

设f[i]表示二进制从小到大第(i+1)位为1时,满足条件的个数
\(f[i]=\sum f[j]|0\le j \le i-2\)
边界f[0]=f[1]=1
找下规律发现
f为斐波那契数列
1,1,2,3,5,8,13,21,34...
前缀和s为
1,2,4,7,12,20,33....
可以发现s[i]=f[i+2]-1

Solution

第一问数位dp
第二问矩乘

Code

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <cctype>
#include <algorithm>
using namespace std;
typedef long long LL;
const int M=62;
const LL Q=1000000007;

inline LL rd(){
	LL x=0;bool f=1;char c=getchar();
	for(;!isdigit(c);c=getchar()) if(c=='-') f=1;
	for(;isdigit(c);c=getchar()) x=x*10+c-48;
	return f?x:-x;
}

int tcas;
LL  n;
int Bit;
LL f[M];

LL pluss(LL x,LL y){
	return (x+y)%Q;
}

LL mul(LL x,LL y){
	return (x*y)%Q;
}

struct G{
	LL a[2][2];
	G(){memset(a,0,sizeof(a));}
}a,b;
G operator *(G x,G y){
	G z;
	int i,j,k;
	for(k=0;k<=1;k++)
	for(i=0;i<=1;i++)
	for(j=0;j<=1;j++)
		z.a[i][j]=pluss(z.a[i][j],mul(x.a[i][k],y.a[k][j]));
	return z;
}

LL dp(){
	LL res;
	res=f[Bit+1]-1;
	for(int i=Bit-1;i>=0;i--){
		if(n>>i&1){
			res+=(f[i+1]-1)+1;//+1 全0情况 
			if(n>>(i+1)&1) break; 
		}
	}
	return res;
}

LL get(LL tms){
	a.a[0][0]=0; a.a[0][1]=1; a.a[1][0]=1; a.a[1][1]=1;
	b.a[0][0]=1; b.a[1][0]=1; b.a[0][1]=0; b.a[1][1]=0;
	
	for(;tms>0;tms>>=1){
		if(tms&1) b=a*b;
		a=a*a;
	}
	return b.a[1][0];
}

int main(){
	scanf("%d",&tcas);
	f[0]=f[1]=1;
	for(int i=2;i<M;i++) f[i]=f[i-1]+f[i-2];
	while(tcas--){
		n=rd();
		n++;
		double tp=log(n)/log(2);
//		Bit=(int)(log(n)/log(2));//这样就会算错?
		Bit=(int)tp;
		printf("%lld\n",dp());
		n--;
		
		printf("%lld\n",get(n));
	}
}
posted @ 2017-01-22 14:10  _zwl  阅读(168)  评论(0编辑  收藏  举报