zoukankan      html  css  js  c++  java
  • 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
    %lld
    ",dp(n),solve(n));
        }
        return 0;
    }

    +++++++++++++++++++++++++++++++++++++++++++

    +本文作者:luyouqi233。               +

    +欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+

    +++++++++++++++++++++++++++++++++++++++++++

  • 相关阅读:
    刻舟求剑,
    录制时间是不准确的,
    HIV T2
    DNA RNA
    洛谷 P1428 小鱼比可爱
    Codevs 1081 线段树练习2
    Codevs 1080 线段树联系
    Tarjan算法
    Codevs 2611 观光旅游
    洛谷 1865 A%B问题
  • 原文地址:https://www.cnblogs.com/luyouqi233/p/8407303.html
Copyright © 2011-2022 走看看