【BZOJ 3329】Xorequ

【题意】

在这里插入图片描述

【分析】

按位异或有一个性质:若 a ⨁ b = c a \bigoplus b=c ab=c, 则 a ⨁ c = b a \bigoplus c = b ac=b
所以说:
x ⨁ 3 x = 2 x ⟺ x ⨁ 2 x = 3 x ⟺ x ⨁ 2 x = x + 2 x x\bigoplus 3x=2x \Longleftrightarrow x \bigoplus 2x =3x \Longleftrightarrow x \bigoplus 2x=x+2x x3x=2xx2x=3xx2x=x+2x
又有:
2 x ⟺ x &lt; &lt; 1 2x \Longleftrightarrow x&lt;&lt;1 2xx<<1
所以
x ⨁ 2 x = x + 2 x ⟺ x &amp; ( x &lt; &lt; 1 ) = 0 x \bigoplus 2x=x+2x \Longleftrightarrow x \&amp; (x&lt;&lt;1)=0 x2x=x+2xx&(x<<1)=0
即x的二进制不存在相邻的1。
于是,对于第一问,设 f ( i , 0 / 1 ) f(i,0/1) f(i,0/1)为当前做到第 i i i位,前一位为0/1,然后按照题意转移即可。
然而,对于第二问,由于位数太长,所以不能用上面那个方法。
我们设 g ( i ) = f ( i , 0 ) + f ( i , 1 ) g(i)=f(i,0)+f(i,1) g(i)=f(i,0)+f(i,1),然后对 g ( i ) g(i) g(i)变形:
g ( i ) = f ( i , 0 ) + f ( i , 1 ) = f ( i − 1 , 0 ) + f ( i − 1 , 1 ) + f ( i − 1 , 0 ) = g ( i − 1 ) + f ( i − 2 , 0 ) + f ( i − 2 , 1 ) = g ( i − 1 ) + g ( i − 2 ) \begin{aligned} g(i)&amp;=f(i,0)+f(i,1)\\&amp;=f(i-1,0)+f(i-1,1)+f(i-1,0)\\&amp;=g(i-1)+f(i-2,0)+f(i-2,1)\\&amp;=g(i-1)+g(i-2) \end{aligned} g(i)=f(i,0)+f(i,1)=f(i1,0)+f(i1,1)+f(i1,0)=g(i1)+f(i2,0)+f(i2,1)=g(i1)+g(i2)
其中:
g ( 1 ) = 2 , g ( 2 ) = 3 g(1)=2,g(2)=3 g(1)=2,g(2)=3
发现这是一个斐波那契数列, g ( i ) g(i) g(i)为其 i + 2 i+2 i+2项,直接矩阵加速即可。

【代码】
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define ll long long
using namespace std;
const int mn = 100, mod = 1e9 + 7;
struct matrix{
    ll a[3][3];
    matrix operator *(const matrix b) const
    {
        matrix c;
        memset(c.a, 0, sizeof c.a);
        for(int i = 1; i <= 2; i++)
            for(int j = 1; j <= 2; j++)
                for(int k = 1; k <= 2; k++)
                    c.a[i][j] += (a[i][k] * b.a[k][j]) % mod, c.a[i][j] %= mod;
        return c;
    }
}ret, h;
int d[mn];
ll f[mn][2];
ll dp(int pos, int las, bool lim)
{
    if(!pos)
        return 1;
    if(!lim && ~f[pos][las])
        return f[pos][las];
    int m = lim ? d[pos] : 1;
    ll ans = 0;
    for(int i = 0; i <= m; i++)
        if(las == 1 && i == 1)
            continue;
        else
            ans += dp(pos - 1, i, lim && i == m);
    if(!lim)
        f[pos][las] = ans;
    return ans;
}
inline ll calc(ll n)
{
    int cnt = 0;
    while(n)
        d[++cnt] = n & 1, n >>= 1;
    return dp(cnt, -1, 1);
}
inline ll ksm(ll b)
{
    while(b)
    {
        if(b & 1)
            ret = ret * h;
        h = h * h, b >>= 1;
    }
    memset(h.a, 0, sizeof h.a);
    h.a[1][1] = 1, h = h * ret;
    return h.a[1][1];
}
inline void init()
{
    memset(ret.a, 0, sizeof ret.a), memset(h.a, 0, sizeof h.a);
    ret.a[1][1] = ret.a[2][2] = 1, h.a[1][1] = h.a[2][1] = h.a[1][2] = 1;
}
int main()
{
    int t;
    ll n;
    scanf("%d", &t), memset(f, -1, sizeof f);
    while(t--)
    {
        scanf("%lld", &n), init();
        printf("%lld\n%lld\n", calc(n) - 1, ksm(n + 1));
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值