【BZOJ】3329: Xorequ
【题意】给定方程x^3x=2x,求<=x和<=2^x的满足方程的正整数个数。
【算法】数位DP,矩阵快速幂
【题解】异或相当于不进位加法。
移项得,x^2x=3x,又因为x+2x=3x,所以x+2x不能产生进位。
又2x=x<<1,所以x+(x<<1)不进位当且仅当x中不存在相邻的1。
问题转化为求<=x的二进制不存在相邻1的正整数个数,state记录前一位为0或1,进行简单的数位DP。(递推的话就表示最高位,然后从下一位对应转移)
第二个问题,设2^x的答案为f[x],最高位为x。若x位为0,则ans=f[x-1]。若x位为1,则x-1位为0,ans=f[x-2]。
所以,f[x]=f[x-1]+f[x-2],用矩阵快速幂求解斐波那契数列。
#include<cstdio> #include<cstring> #include<algorithm> #define ll long long using namespace std; const int maxn=100,MOD=1e9+7; ll f[maxn][maxn],n,ans[5][5],A[5][5],c[5][5]; int a[maxn]; ll dfs(int pos,int state,int limit){ if(pos==-1)return 1; if(!limit&&~f[pos][state])return f[pos][state]; ll sum=dfs(pos-1,0,limit&&a[pos]==0); if((!limit||a[pos]==1)&&state==0)sum+=dfs(pos-1,1,limit); if(!limit)f[pos][state]=sum; return sum; } void mul(ll A[5][5],ll B[5][5]){ for(int i=0;i<2;i++) for(int j=0;j<2;j++){ c[i][j]=0; for(int k=0;k<2;k++) c[i][j]=(c[i][j]+B[i][k]*A[k][j])%MOD; } for(int i=0;i<2;i++) for(int j=0;j<2;j++) A[i][j]=c[i][j]; } ll ask(ll x){ ans[0][0]=ans[1][0]=1;ans[0][1]=ans[1][1]=0; A[0][0]=A[0][1]=A[1][0]=1;A[1][1]=0; while(x){ if(x&1)mul(ans,A); mul(A,A); x>>=1; } return ans[0][0]; } int main(){ int T; scanf("%d",&T); memset(f,-1,sizeof(f)); while(T--){ scanf("%lld",&n); ll num=n;// int len=0; while(num){ a[len++]=num%2; num/=2; } printf("%lld\n%lld\n",dfs(len-1,0,1)-1,ask(n)); } return 0; }
注意long long。