【bzoj3329】【Xorequ】【数位dp+矩阵乘法】

来源:互联网 发布:gta5n卡掉帧如何优化 编辑:程序博客网 时间:2024/06/05 02:56

Description

Input

第一行一个正整数,表示数据组数据 ,接下来T行
每行一个正整数N

Output

2*T行
第2*i-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^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 longusing 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));  }}

  

0 0
原创粉丝点击