[BZOJ3329]Xorequ(数位DP+矩阵快速幂)
好题好题!(又被模数坑了(大雾。。。))
首先第一问我就死了,把式子全搞到了一边,然后发现那个乘3的非常难做,于是打表找规律。
可以很显然地发现:第二问是个fibonacci数列,很激动,但并没有什么卵用,没有部分分这个题。
第一问其实是化为了问有多少个数在二进制下没有相邻的1,这样就可以用数位DP做了。
dfs记录处理到第几位,上一个是什么,是否受限,是否为最高位,很套路(注意不要取模,那个是第二问的)
1 //第一问没有相邻的1? 2 //第二问fibonacci(n+2)项? 3 #include<iostream> 4 #include<cstdio> 5 #include<cmath> 6 #include<algorithm> 7 #include<queue> 8 #include<vector> 9 #include<string> 10 #include<cstring> 11 #include<map> 12 #define int long long 13 #define max(a,b) (a>b?a:b) 14 #define min(a,b) (a>b?b:a) 15 #define m(a) memset(a,0,sizeof(a)) 16 #define AA cout<<"Alita"<<endl 17 using namespace std; 18 const int mod=1e9+7; 19 int n,len,T,ans1,ans2,f[65][15][2][2]; 20 struct Ma{int f[5][5];}A,B,S; 21 int dfs(int x,int y,int z,int k) 22 { 23 if(!x) return 1; 24 if(f[x][y][z][k]!=-1) return f[x][y][z][k]; 25 f[x][y][z][k]=0; 26 if(k) 27 { 28 f[x][y][z][k]+=dfs(x-1,1,0,0); 29 f[x][y][z][k]+=dfs(x-1,0,0,1); 30 return f[x][y][z][k]; 31 } 32 if(z) 33 { 34 if(n&(1ll<<(x-1))) 35 { 36 if(!y) f[x][y][z][k]+=dfs(x-1,1,1,0); 37 f[x][y][z][k]+=dfs(x-1,0,0,0); 38 } 39 else 40 { 41 f[x][y][z][k]+=dfs(x-1,0,1,0); 42 } 43 } 44 else 45 { 46 if(!y) f[x][y][z][k]+=dfs(x-1,1,0,0); 47 f[x][y][z][k]+=dfs(x-1,0,0,0); 48 } 49 return f[x][y][z][k]; 50 } 51 Ma X(Ma x,Ma y) 52 { 53 Ma ans;m(ans.f); 54 for(int i=1;i<=2;i++) 55 { 56 for(int j=1;j<=2;j++) 57 { 58 for(int k=1;k<=2;k++) 59 { 60 (ans.f[i][j]+=x.f[i][k]*y.f[k][j]%mod)%=mod; 61 } 62 } 63 } 64 return ans; 65 } 66 int FI(int x) 67 { 68 m(A.f);m(B.f);m(S.f); 69 A.f[1][1]=0;A.f[1][2]=1; 70 A.f[2][1]=1;A.f[2][2]=1; 71 B.f[1][1]=0;B.f[2][1]=1; 72 S.f[1][1]=1;S.f[2][2]=1; 73 while(x) 74 { 75 if(x&1) S=X(S,A); 76 x>>=1; 77 A=X(A,A); 78 } 79 B=X(S,B); 80 return B.f[2][1]; 81 } 82 void work() 83 { 84 memset(f,-1,sizeof(f)); 85 len=0; 86 scanf("%lld",&n); 87 int tmp=n; 88 while(tmp) 89 { 90 len++; 91 tmp>>=1; 92 } 93 ans1=dfs(len-1,1,1,0)+dfs(len-1,0,0,1)-1; 94 ans2=FI(n+1); 95 printf("%lld\n%lld\n",ans1,ans2); 96 } 97 signed main() 98 { 99 //freopen("1.in","r",stdin); 100 //freopen("1.out","w",stdout); 101 scanf("%lld",&T); 102 while(T--) work(); 103 return 0; 104 }