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));
}
}