【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;
}
View Code

注意long long。

posted @ 2017-10-26 20:51  ONION_CYC  阅读(151)  评论(0编辑  收藏  举报