[BZOJ3329] Xorequ
题解:
网上的方法基本是建立在发现临位不能相等的基础上的
这个很好证。。
但是不利用这个特征也是可以的
x^2x=3x
我们考虑二进制的前i位,我们会发现3x最多涉及到了前i+2位
于是我们可以记录一下前i位的3x的i+1,i+2位的状态,以及第i位填了什么
因为后面的位置是不影响前面的位置的,所以前面必须要匹配
然后这个东西数位dp一下(数位dp正着做反着做其实也差不多)
这个dp只要你头脑清醒还是比较好打的。。。。
对于第二问这种东西很明显是找规律
fib数列,用正解很容易证明,矩阵求一下就好
代码:
#include <bits/stdc++.h> using namespace std; #define rint register ll #define IL inline #define rep(i,h,t) for (rint i=h;i<=t;i++) #define dep(i,t,h) for (rint i=t;i>=h;i--) #define ll long long const ll mo=1e9+7; ll n,v[100],f[100][4][2][2]; struct re{ ll a[2][2]; re() { a[0][0]=a[0][1]=a[1][0]=a[1][1]=0;}; }now; re js(re x,re y) { re a; rep(i,0,1) rep(j,0,1) rep(k,0,1) a.a[i][k]+=x.a[i][j]*y.a[j][k],a.a[i][k]%=mo; return(a); } re fsp(ll x) { if (x==1) return(now); re k1=fsp(x/2); k1=js(k1,k1); if (x%2) k1=js(k1,now); return(k1); } int main() { freopen("1.in","r",stdin); freopen("1.out","w",stdout); ios::sync_with_stdio(false); ll T; now.a[0][0]=1; now.a[0][1]=1; now.a[1][0]=1; now.a[1][1]=0; cin>>T; rep(kk,1,T) { memset(f,0,sizeof(f)); cin>>n; ll l=0,tmp=n; while (tmp) l++,v[l]=tmp%2,tmp/=2; f[0][0][0][0]=1; rep(i,1,l) { if (v[i]==1) { f[i][3][1][1]=f[i-1][3][1][1]; f[i][3][1][0]=f[i-1][3][1][0]; f[i][2][1][1]=f[i-1][2][0][1]; f[i][2][1][0]=f[i-1][2][0][0]; f[i][1][1][1]=f[i-1][0][0][1]; f[i][1][1][0]=f[i-1][0][0][0]; f[i][1][0][0]=f[i-1][3][1][0]+f[i-1][3][1][1] +f[i-1][2][0][1]+f[i-1][2][0][0]; f[i][0][0][0]=f[i-1][1][1][0]+f[i-1][1][1][1] +f[i-1][0][0][0]+f[i-1][0][0][1]; } else { f[i][3][1][1]=f[i-1][3][1][1]+f[i-1][3][1][0]; f[i][2][1][1]=f[i-1][2][0][1]+f[i-1][2][0][0]; f[i][1][1][1]=f[i-1][0][0][1]+f[i-1][0][0][0]; f[i][1][0][0]=f[i-1][3][1][0]+f[i-1][2][0][0]; f[i][1][0][1]=f[i-1][3][1][1]+f[i-1][2][0][1]; f[i][0][0][0]=f[i-1][1][1][0]+f[i-1][0][0][0]; f[i][0][0][1]=f[i-1][1][1][1]+f[i-1][0][0][1]; } } cout<<f[l][1][1][0]+f[l][0][0][0]-1<<endl; cout<<fsp(n+1).a[0][0]<<endl; } return 0; }