Description
Input
第一行一个正整数,表示数据组数据 ,接下来T行
每行一个正整数N
Output
2*T行
第2*i-1行表示第i个数据中问题一的解,
第2*i行表示第i个数据中问题二的解,
Sample Input
1
1
1
Sample Output
1
2
2
HINT
x=1与x=2都是原方程的根,注意第一个问题的解
不要mod 10^9+7
1<=N<=10^18
1<=T<=1000
题解:x^3x=2x等价于x^2x=3x;
显然2x=x<<1;
所以如果等式成立必然x&(x<<1)=0;
即x中不存在相邻的1.
设f[i]表示0开头符合条件的数的个数。
g[i]表示1开头符合条件的数的个数。
则f[i]=f[i-1]+g[i-1]
g[i]=f[i-1];
然后第一问我们可以数位dp。
第二问答案就是f[n+1],矩乘一下即可。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#define P 1000000007
#define ll long long
using namespace std;
ll g[100],x,f[100],T;
struct use{
ll a[2][2];
use(){memset(a,0,sizeof(a));}
friend use operator*(use a,use b){
use ans;
for (int i=0;i<=1;i++)
for (int j=0;j<=1;j++)
for (int k=0;k<=1;k++)
(ans.a[i][j]+=a.a[i][k]*b.a[k][j]%P)%=P;
return ans;
}
friend use operator^(use a,ll b){
use ans;ans.a[0][0]=ans.a[1][1]=1;
for (ll i=b;i;i>>=1,a=a*a) if (i&1) ans=ans*a;
return ans;
}
}a,ans;
ll dp(ll x){
int t(0),flag(0);
ll ans(0);
for (t=0;1ll<<t<=x;t++);
for(;t;t--){
//cout<<x<<' '<<t<<endl;
if (x&(1ll<<t-1)){
ans+=f[t];
if (flag) return ans-1;
flag=1;
}
else flag=0;
}
return ans-1;
}
ll cal(ll x){
a.a[0][0]=a.a[0][1]=a.a[1][0]=1;a.a[1][1]=0;
a=a^x;
return (a.a[0][0]+a.a[0][1])%P;
}
int main(){
f[0]=1;
for (int i=1;i<=63;i++)
f[i]=f[i-1]+g[i-1],g[i]=f[i-1];
scanf("%d",&T);
while (T--){
scanf("%lld",&x);
printf("%lld\n",dp(x+1));
printf("%lld\n",cal(x));
}
}