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