bzoj3329 Xorequ

3329: Xorequ

Time Limit: 1 Sec  Memory Limit: 256 MB
Submit: 1427  Solved: 601
[Submit][Status][Discuss]

Description

Input

第一行一个正整数,表示数据组数据 ,接下来T行
每行一个正整数N

Output

2*T行
第2*i-1行表示第i个数据中问题一的解,

第2*i行表示第i个数据中问题二的解,

Sample Input

1
1

Sample Output

1
2

HINT

x=1与x=2都是原方程的根,注意第一个问题的解
不要mod 10^9+7

1<=N<=10^18 
1<=T<=1000

Source

By Wcmg

分析:好题.

   第一问考察对二进制数的运算的一些性质的掌握.

   因为a xor b = c等价于 a xor c = b,所以方程可以变形为x xor 2x = 3x. 

   既然涉及到xor运算,就要以二进制的视角去研究这些数. 2x可以看作x左移一位得到. 

   观察发现3x = x + 2x,那么x xor 2x = x + 2x.

   xor又叫二进制运算中不进位的加法.不能进位,说明没有1在一起,而2x是由x左移得到的,所以可以得到结论:x不能有连续的1存在.可以用数位dp解决.

   第二问就考验找规律能力了. 这个数可能有10^18位,数位dp都处理不了了......也没有别的方法了,只能找规律. 找几个小点的n,很容易就能发现答案就是斐波那契数列的第n+2项,矩阵快速幂就能搞定.

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

typedef long long ll;
const ll mod = 1e9 + 7;
ll T,n,ans,num[1100],tot,f[1100][2];

struct node
{
    ll x[3][3];
    void clear()
    {
        memset(x,0,sizeof(x));
    }
}a,b,c;

void operator *= (node &p,node &q)
{
    c.clear();
    for (int i = 1; i <= 2; i++)
        for (int j = 1; j <= 2; j++)
            for (int k = 1; k <= 2; k++)
                c.x[i][j] = (c.x[i][j] + p.x[i][k] * q.x[k][j] % mod) % mod;
    p = c;
}

ll dfs(ll len,ll if1,bool limit)
{
    if (len == 0)
        return 1;
    if (!limit && ~f[len][if1])
        return f[len][if1];
    ll shangxian = (limit ? num[len] : 1),cnt = 0;
    for (ll i = 0; i <= shangxian; i++)
    {
        if (i == 0 || if1 == 0)
        cnt += dfs(len - 1,i,(limit && i == shangxian));
    }
    if (limit)
        return cnt;
    else
        return f[len][if1] = cnt;
}

ll solve1()
{
    tot = 0;
    ll x = n;
    while (x)
    {
        num[++tot] = x % 2;
        x /= 2;
    }
    return dfs(tot,0,1);
}

void init()
{
    tot = 0;
    memset(num,0,sizeof(num));
    memset(f,-1,sizeof(f));
    ans = 0;
}

void qpow(ll c)
{
    while (c)
    {
        if (c & 1)
            a *= b;
        b *= b;
        c >>= 1;
    }
}

void solve2()
{
    a.clear();
    b.clear();
    a.x[1][1] = 1;
    a.x[2][2] = 1;
    b.x[1][1] = 1;
    b.x[1][2] = 1;
    b.x[2][1] = 1;
    qpow(n + 1);
    ans = a.x[1][1];
}

int main()
{
    scanf("%lld",&T);
    while (T--)
    {
        init();
        scanf("%lld",&n);
        printf("%lld\n",solve1() - 1);
        solve2();
        printf("%lld\n",ans);
    }

    return 0;
}

 

 

posted @ 2018-02-23 15:28  zbtrs  阅读(206)  评论(0编辑  收藏  举报