bzoj3329 Xorequ

Xorequ

Time Limit: 1 Sec Memory Limit: 256 MB

Description

Input

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

Output

2T行
第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



我就服这个简单的数位dp。。。。
大概就是洗澡的时候瞎脑补了个算法。。。反正我很菜就是了。。。
矩阵快速幂没清零的我是不是很强???


#include<bits/stdc++.h>
using namespace std;
const int mod = 1e9 + 7;
struct lpl{
    int n, m;
    long long a[3][3];
}lin;
long long n;
long long f[66][2], pw[66];
int num[66];

lpl operator * (const lpl &A, const lpl &B)
{
    lpl ret; ret.n = A.n; ret.m = B.m;
    memset(ret.a, 0, sizeof(ret.a));
    for(int i = 1; i <= ret.n; ++i)
        for(int j = 1; j <= ret.m; ++j)
            for(int k = 1; k <= A.m; ++k)
                ret.a[i][j] = (ret.a[i][j] + A.a[i][k] * B.a[k][j] % mod) % mod;
    return ret;
}

inline void prepare()
{
    f[1][0] = 1; f[1][1] = 1; pw[0] = 1; pw[1] = 2;
    for(int i = 2; i <= 63; ++i){
        pw[i] = (pw[i - 1] << 1);
        f[i][0] = f[i - 1][0] + f[i - 1][1];
        f[i][1] = f[i - 1][0];
    }
}

inline long long workk1(long long t)
{
    long long ret = 0;
    int len = 62;
    while(pw[len] > t) len--;
    for(int i = 1; i <= len + 1; ++i){
        num[i] = (t & 1); t >>= 1;
    }
    num[len + 2] = 0;
    for(int i = len + 1; i >= 1; --i){
        if(num[i]){
            ret += f[i][0];
            if(num[i + 1]){
                ret--; break;
            }
        }
    }
    return ret;
}

inline long long workk2(long long t)
{
    lpl ret;
    lin.a[1][1] = lin.a[1][2] = lin.a[2][1] = 1; lin.a[2][2] = 0; lin.n = lin.m = 2;
    ret.a[1][1] = ret.a[2][2] = 1; ret.a[1][2] = ret.a[2][1] = 0; ret.n = ret.m = 2;
    while(t){
        if(t & 1) 
        ret = ret * lin;
        t >>= 1; lin = lin * lin;
    }
    lpl ans; ans.n = 2; ans.m = 1; ans.a[1][1] = ans.a[2][1] = 1; ans.a[1][2] = ans.a[2][2] = 0;
    ans = ret * ans;
    return ans.a[1][1];
}

int main()
{
    prepare();
    int T; scanf("%d", &T);
    while(T--){
        scanf("%lld", &n);
        printf("%lld\n%lld\n", workk1(n), workk2(n));
    } 
    return 0;
} 

猜你喜欢

转载自www.cnblogs.com/LLppdd/p/9146662.html