BZOJ3329 : Xorequ

第一问:

打表可得规律:当且仅当x&(x<<1)=0时才会是解,于是数位DP

f[i][j][k]表示二进制中前i位,上一位是j,前i位是否等于n的方案数

第二问:

打表可得规律:答案为斐波那契数列第n+2项,矩阵快速幂即可

 

#include<cstdio>
typedef long long ll;
struct mat{
  ll a[2][2];
  mat(){a[0][0]=a[0][1]=a[1][0]=a[1][1]=0;}
  mat operator*(mat b){
    mat c;
    for(int i=0,j,k;i<2;i++)for(j=0;j<2;j++)for(k=0;k<2;k++)(c.a[i][j]+=a[i][k]*b.a[k][j])%=1000000007;
    return c;
  }
}A,B,C;
int T,a[65],len,i,j,t;ll n,x,tmp,f[65][2][2];
int main(){
  scanf("%d",&T);
  while(T--){
    scanf("%lld",&x);
    for(len=0,tmp=x;tmp;a[++len]=tmp&1LL,tmp>>=1LL);
    for(i=1,j=len;i<=len&&i<j;i++,j--)t=a[i],a[i]=a[j],a[j]=t;
    for(i=1;i<=len;i++)f[i][0][0]=f[i][1][0]=f[i][0][1]=f[i][1][1]=0;
    for(i=0;i<=1;i++)f[1][i][i==a[1]]=1;
    for(i=1;i<len;i++){
      if(f[i][0][0])for(j=0;j<=1;j++)f[i+1][j][0]+=f[i][0][0];
      if(f[i][1][0])for(j=0;j<=0;j++)f[i+1][j][0]+=f[i][1][0];
      if(f[i][0][1])for(j=0;j<=a[i+1];j++)f[i+1][j][j==a[i+1]]+=f[i][0][1];
      if(f[i][1][1])for(j=0;j<=0;j++)f[i+1][j][j==a[i+1]]+=f[i][1][1];
    }
    printf("%lld\n",f[len][0][0]+f[len][1][0]+f[len][0][1]+f[len][1][1]-1);
    for(A=B=C=mat(),A.a[0][1]=A.a[1][0]=A.a[1][1]=B.a[0][0]=C.a[0][0]=C.a[1][1]=1,B.a[1][0]=2;x;x>>=1LL,A=A*A)if(x&1LL)C=C*A;
    C=C*B;
    printf("%lld\n",C.a[0][0]);
  }
  return 0;
}

  

 

posted @ 2014-12-15 18:21  Claris  阅读(771)  评论(0编辑  收藏  举报