[BZOJ3329] Xorequ
[BZOJ3329] Xorequ
Description
Input
第一行一个正整数,表示数据组数据 ,接下来T行每行一个正整数N
Output
2T行第2i-1行表示第i个数据中问题一的解,第2*i行表示第i个数据中问题二的解,
Sample Input
1
1
Sample Output
1
2
HINT
x=1与x=2都是原方程的根,注意第一个问题的解不要mod 10^9+7
1<=N<=10^18
1<=T<=1000
试题分析
由于我们有式子\(x\oplus 3x = 2x\),可以尝试进行推导。
由于\(x\oplus x = 0\),\(0 \oplus x = 0\),可推导出:$$x\oplus 2x = 3x$$
3x就相当于是x的二进制位上的所有1前面再加一个1,然后再考虑进位。
但\(x\oplus 2x = 3x\),由于\(2x\)为\(x\)右移一位,相当于效果与\(3x\)相同。
因此可以证明没有进位,也就是说一个数没有1的位相邻。
对于第二问,打一个表推推式子矩阵快速幂一下。
强行二合一
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
#define LL long long
inline LL read(){
LL x=0,f=1; char c=getchar();
for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
for(;isdigit(c);c=getchar()) x=x*10+c-'0';
return x*f;
}
const LL MAXN = 1000010;
const LL INF = 2147483600;
const LL Mod = 1e9+7;
LL N,K,M,P,TT;
LL a[101][101],b[101][101],c[101][101];
void Mul1(){
memset(b,0,sizeof(b));
for(LL i=1;i<=N;i++)
for(LL j=1;j<=M;j++)
for(LL k=1;k<=K;k++)
b[i][j]+=a[i][k]*c[k][j]%Mod,b[i][j]%=Mod;
for(LL i=1;i<=N;i++){
c[i][1]=b[i][1];
}
return ;
}
void Mul2(){
memset(b,0,sizeof(b));
for(LL i=1;i<=N;i++)
for(LL j=1;j<=N;j++)
for(LL k=1;k<=N;k++)
b[i][j]+=a[i][k]*a[k][j]%Mod,b[i][j]%=Mod;
for(LL i=1;i<=N;i++){
for(LL j=1;j<=N;j++)
a[i][j]=b[i][j];
}
return ;
}
LL dp[67][2][2]; LL str[MAXN+1];LL cnt=0;
inline void split(LL x){
while(x){
str[++cnt]=(x&1);
x=x>>1;
} while(cnt<=64) str[++cnt]=0;
//for(LL i=1;i<=cnt/2;i++) swap(str[i],str[cnt-i+1]);
//for(int i=cnt;i>=1;i--) cout<<str[i]; cout<<endl;
}
LL ans;
int main(){
//freopen(".in","r",stdin);
//freopen(".out","w",stdout);
int T=read(); dp[0][0][0]=1;
for(LL i=0;i<65;i++){
for(LL j=0;j<2;j++){
for(LL k=0;k<2;k++){
//cout<<dp[i][j][k]<<":"<<i<<" "<<j<<" "<<k<<endl;
if(j==1&&k==1) continue;
dp[i+1][0][j]+=dp[i][j][k];
if(!j) dp[i+1][1][j]+=dp[i][j][k];
}
}
}
while(T--){
P=TT=read();
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
memset(c,0,sizeof(c));
N=2; M=1; K=2;
a[1][1]=a[1][2]=1; a[2][1]=1;
c[1][1]=1; c[2][1]=1; ++P;
while(P){
if(P&1) Mul1(); P>>=1;
Mul2();
} N=TT; cnt=0;
split(N); ans=0;
for(LL i=cnt;i>=2;i--){
if(str[i]==1)
ans+=dp[i][0][0]+dp[i][0][1];
if(str[i-1]==str[i]&&str[i-1]==1) {ans+=dp[i][1][0]; break;}
if(i==2){++ans; ans+=str[i-1]; }
}
if(N!=1) printf("%lld\n",ans-1);
else printf("%lld\n",1LL);
printf("%lld\n",c[2][1]%Mod);
}
return 0;
}
你——悟到了么?