BZOJ3329:Xorequ——题解
http://www.lydsy.com/JudgeOnline/problem.php?id=3329
原式化为x^2x=3x,而且实际上异或就是不进位的加法。
那么我们又有x+2x=3x,所以在做加法的时候也没有(在二进制中)进位。
由此我们得到:x必须(在二进制下)没有相邻的1。
那么第一问我们可以采用数位dp,相信看这篇博客的你一定会了数位dp,不会的话设f[i][j][0/1]表示第i位放j数,且前i位比n的前i位小于等于/大于。
剩下的就去学数位dp吧。
第二问就相当于问符合条件的长度为n的01串个数,可以打表,也可以感性证明一下发现就是fib的第n+2项。
于是愉快的矩阵乘法。
#include<cmath> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; typedef long long ll; const ll p=1e9+7; ll f[100][2][2]; int q[100]; ll dp(ll x){ int len=0; while(x)q[++len]=x%2,x/=2; if(len==0)q[++len]=0; memset(f,0,sizeof(f)); for(int i=0;i<=1;i++){ if(i<=q[1])f[1][i][0]=1; else f[1][i][1]=1; } for(int i=2;i<=len;i++){ for(int j=0;j<=1;j++){ for(int k=0;k<=1;k++){ if(j+k!=2){ if(j<q[i]) f[i][j][0]+=f[i-1][k][0]+f[i-1][k][1]; else if(j==q[i]) f[i][j][0]+=f[i-1][k][0],f[i][j][1]+=f[i-1][k][1]; else f[i][j][1]+=f[i-1][k][0]+f[i-1][k][1]; } } } } ll ans=f[len][1][0]; for(int i=len-1;i;i--)ans+=f[i][1][0]+f[i][1][1]; return ans; } struct node{ ll g[2][2]; }; void buildI(node &a){ for(int i=0;i<2;i++){ for(int j=0;j<2;j++){ a.g[i][j]=(i==j); } } } void multi(node x,node y,node &z){ memset(z.g,0,sizeof(z.g)); for(int i=0;i<2;i++){ for(int j=0;j<2;j++){ if(x.g[i][j]){ for(int l=0;l<2;l++){ z.g[i][l]+=x.g[i][j]%p*y.g[j][l]%p; z.g[i][l]%=p; } } } } return; } node a,b; void qpow(ll k){ buildI(a); while(k){ if(k&1)multi(a,b,a); multi(b,b,b); k>>=1; } return; } ll solve(ll n){ b.g[0][0]=1;b.g[0][1]=1; b.g[1][0]=1;b.g[1][1]=0; qpow(n+2); return a.g[0][1]%p; } ll t,n; int main(){ scanf("%lld",&t); while(t--){ scanf("%lld",&n); printf("%lld\n%lld\n",dp(n),solve(n)); } return 0; }
+++++++++++++++++++++++++++++++++++++++++++
+本文作者:luyouqi233。 +
+欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+
+++++++++++++++++++++++++++++++++++++++++++