BZOJ 2656 ZJOI 2012 数列(sequence) 高精度+记忆化搜索

题目大意:定义个一序列,f[i] = f[i / 2] (i % 2 == 0);f[i] = f[i / 2] + f[i / 2 + 1] (i % 2 == 1);求这个数列的第m项(m <= 10 ^ 100)

思路:数据范围高精度没跑了。记得之前做过这个题的弱化版,似乎是没有高精度的记忆化搜索,这个题就是加个高精度。

CODE:

#include <map>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAX 210
#define MO 10
using namespace std;
#define max(a,b) ((a) > (b) ? (a):(b))

class BigInt{
private:
    int num[MAX],len;
public:
    BigInt(int _ = 0) {
        memset(num,0,sizeof(num));
        num[len = 1] = _;
    }
    void Read() {
        static char s[MAX];
        scanf("%s",s);
        len = strlen(s);
        for(int i = 1; i <= len; ++i)
            num[i] = s[len - i] - '0';
    }
    friend ostream &operator <<(ostream &os,const BigInt &a);
    bool operator <(const BigInt &a)const {
        if(len == a.len) {
            for(int i = len; i; --i)
                if(num[i] != a.num[i])
                    return num[i] < a.num[i];
        }
        return len < a.len;
    }
    bool Odd()const {
        return num[1]&1;
    }
    BigInt operator +(const BigInt &a)const {
        BigInt re;
        re.len = max(len,a.len);
        int temp = 0;
        for(int i = 1; i <= re.len; ++i) {
            re.num[i] = temp + num[i] + a.num[i];
            temp = re.num[i] / MO;
            re.num[i] %= MO;
        }
        if(temp)    re.num[++re.len] = temp;
        return re;
    }
    BigInt operator /(int c)const {
        BigInt re;
        re.len = len;
        int temp = 0;
        for(int i = len; i; --i) {
            re.num[i] = (num[i] + temp) / 2;
            temp = (num[i] + temp) % 2 * MO;
        }
        while(!re.num[re.len])  --re.len;
        return re;
    }
}temp;

ostream &operator <<(ostream &os,const BigInt &a)
{
    os << a.num[a.len];
    for(int i = a.len - 1; i; --i)
        os << a.num[i];
    return os;
}

map<BigInt,BigInt> G;

int T;

BigInt &MemorialSearch(const BigInt &a)
{
    if(G.find(a) != G.end())    return G[a];
    if(a.Odd())
        G[a] = MemorialSearch(a / 2) + MemorialSearch(a / 2 + 1);
    else    G[a] = MemorialSearch(a / 2);
    return G[a];
}

int main()
{
    G[0] = BigInt(0);
    G[1] = BigInt(1);
    for(cin >> T; T--;) {
        temp.Read();
        cout << MemorialSearch(temp) << endl;
    }
    return 0;
}

时间: 2024-10-14 01:20:38

BZOJ 2656 ZJOI 2012 数列(sequence) 高精度+记忆化搜索的相关文章

BZOJ 2656 ZJOI2012 数列(sequence) 高精度+记忆化搜索

题目大意:给定一个数列的通项公式,求数列的某一项 高精度+记忆化搜索没说的 其实不用记忆化搜索的但是既然写完了就写完了吧 顺便学习了一下友元函数之类的东西- - #include <map> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; class Big_Int{ private: int nu

BZOJ 3208 花神的秒题计划Ⅰ 记忆化搜索

题目大意:给定一个矩阵,多次改变某个点的权值,设定某个子矩阵内的所有点可用/禁用,求滑雪的最大长度 再也不敢不看数据范围就做题了233333 #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define M 710 using namespace std; const int dx[]={0,0,1,-1}; const int dy[]={1,-1

[ZJOI 2012]数列

Description 题库链接 给你一个数列 \(A\),满足递推公式 \[ A_n\left\{\begin{aligned}&0,&n=0\\&1,&n=1\\&A_\frac{n}{2},&2\mid n\\&A_{\left\lfloor\frac{n}{2}\right\rfloor}+A_{\left\lceil\frac{n}{2}\right\rceil},&\text{else}\end{aligned}\right. \

[BZOJ 1055] [HAOI2008] 玩具取名 【记忆化搜索】

题目链接:BZOJ - 1055 题目分析 这种类似区间 DP 的记忆化搜索都是很相近的,比如字符串压缩和字符串扩展都差不多. 都是将现在 Solve 的区间分成子区间,再求解子区间. 这道题 Solve(l, r, x) 求能否将 [l, r] 的区间还原成 x ,那么就将它分成两段,看是否能左段变成 p , 右段变成 q. (x 能变成 pq) 代码 #include <iostream> #include <cstdio> #include <cstdlib> #

记忆化搜索+DFS URAL 1183 Brackets Sequence

题目传送门 1 /* 2 记忆化搜索+DFS:dp[i][j] 表示第i到第j个字符,最少要加多少个括号 3 dp[x][x] = 1 一定要加一个括号:dp[x][y] = 0, x > y; 4 当s[x] 与 s[y] 匹配,则搜索 (x+1, y-1); 否则在x~y-1枚举找到相匹配的括号,更新最小值 5 */ 6 #include <cstdio> 7 #include <algorithm> 8 #include <cmath> 9 #include

[BZOJ 1048] [HAOI2007] 分割矩阵 【记忆化搜索】

题目链接:BZOJ - 1048 题目分析 感觉这种分割矩阵之类的题目很多都是这样子的. 方差中用到的平均数是可以直接算出来的,然后记忆化搜索 Solve(x, xx, y, yy, k) 表示横坐标范围 [x, xx], 纵坐标范围 [y, yy] 的矩阵切成 k 块的最小 sigma((Vi - Ave)^2) . 然后再递归将矩阵分得更小,直到 k 为 1 的时候直接返回相应的值. 代码 #include <iostream> #include <cstdlib> #incl

BZOJ 1079: [SCOI2008]着色方案 记忆化搜索

1079: [SCOI2008]着色方案 Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/problem.php?id=1079 Description 有n个木块排成一行,从左到右依次编号为1~n.你有k种颜色的油漆,其中第i种颜色的油漆足够涂ci个木块.所有油漆刚好足够涂满所有木块,即c1+c2+...+ck=n.相邻两个木块涂相同色显得很难看,所以你希望统计任意两个相邻木块颜色不同的

BZOJ 1415 NOI2005 聪聪和可可 期望DP+记忆化搜索 BZOJ200题达成&amp;&amp;NOI2005全AC达成

题目大意:给定一个无向图,聪聪在起点,可可在终点,每个时刻聪聪会沿最短路走向可可两步(如果有多条最短路走编号最小的点),然后可可会等概率向周围走或不动,求平均多少个时刻后聪聪和可可相遇 今天早上起床发现194了然后就各种刷--当我发现199的时候我决定把第200题交给05年NOI仅剩的一道题--结果尼玛调了能有一个小时--我居然没看到编号最小这个限制0.0 首先我们知道,由于聪聪走两步而可可走一步,所以聪聪一定能在有限的时刻追上可可,而且两人的距离随着时间进行单调递减 于是我们记忆化搜索 首先用

BZOJ 3895 取石子 博弈论+记忆化搜索

题目大意:给定n堆石子,两人轮流操作,每个人可以合并两堆石子或拿走一个石子,不能操作者输,问是否先手必胜 直接想很难搞,我们不妨来考虑一个特殊情况 假设每堆石子的数量都>1 那么我们定义操作数b为当前石子总数+当前堆数-1 若b为奇数,则先手必胜,否则后手必胜 证明: 若当前只有一堆,则正确性显然 否则: 若b为奇数,那么先手只需进行一次合成操作,此时操作数会-1,且仍不存在大小为1的堆 因此只需要证明b为偶数时先手必败即可 若先手选择了合成操作,那么操作数-1且不存在大小为1的堆,状态回到了b