• ACM学习历程—HDU5587 Array(数学 && 二分 && 记忆化 || 数位DP)(BestCoder Round #64 (div.2) 1003)


    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5587

    题目大意就是初始有一个1,然后每次操作都是先在序列后面添加一个0,然后把原序列添加到0后面,然后从0到末尾,每一个都加上1

    例如:a0, a1, a2 => a0, a1, a2, 1, a0+1, a1+1, a2+1

    题解中是这么说的:“

    其实Ai为i二进制中1的个数。每次变化A{k+2^i}=A{k}+1,(k<2^​i​​)不产生进位,二进制1的个数加1。然后数位dp统计前m个数二进制1的个数,计算每一位对答案的贡献。只需考虑该位填1,其高位与低位的种数即可。

    不过我没有想到这个。

    我写了几次变换后,发现:

    对最前面添加一个0

    于是每次变换长度都变成两倍,而且前后序列每一个对应差值为1

    不过这样前后二分显然对于m+12的次方有要求。

    但是对于每2个组成一组,那么发现,至少每次变换都是以2的倍数个变换的。

    也就是说单看i%2== 1的那些数ai,发现他们组成的序列变换和原序列一模一样。

    i%2== 0的同理,不过需要在每一个数的基础上加上1

    然后对于s(n),自然可以由它前面i%2 == 1, i%2 == 0的两组序列构成

    于是就变成了s(n) = s(n/2)+s(n/2)+n/2 or s(n/2+1)+s(n/2)+n/2(取决于n%2

    这样的话就能二分下去了,不过需要记忆化,这里采用了map进行记忆化。

    不过比赛的时候,我写的是四个为一组。由于上面的n/2n/2+1只有当大量出现n%2等于0了才能每次截掉一半。但是如果四个一组的话,每次长度变成1/4,但是最多生成n/4n/4+1。不过这两种在不记忆化的情况下都会T

    不过用map记忆化后,我怕会MLE,本地测了好几组数据,都没有占很大内存。

    代码:(二分)

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cmath>
    #include <cstring>
    #include <algorithm>
    #include <set>
    #include <map>
    #include <queue>
    #include <string>
    #define LL long long
    
    using namespace std;
    
    LL m;
    map<LL, LL> s;
    
    LL dfs(LL n)
    {
        if (n == 1) return 0;
        if (n == 2) return 1;
        LL ans, t1 = 0, t2;
        if (n%2)
        {
            if (s[n/2+1] == 0)
            {
                t1 = dfs(n/2+1);
                s[n/2+1] = t1;
            }
            else t1 = s[n/2+1];
        }
        if (s[n/2] == 0)
        {
            t2 = dfs(n/2);
            s[n/2] = t2;
        }
        else t2 = s[n/2];
    
        ans = (n%2)*t1+(2-n%2)*t2;
        ans += n/2;
        return ans;
    }
    
    int main()
    {
        //freopen("test.in", "r", stdin);
        int T;
        scanf("%d", &T);
        for (int times = 1; times <= T; ++times)
        {
            scanf("%I64d", &m);
            LL ans;
            ans = dfs(m+1);
            printf("%I64d
    ", ans);
        }
        return 0;
    }
    View Code

    代码:(四分)

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cmath>
    #include <cstring>
    #include <algorithm>
    #include <set>
    #include <map>
    #include <queue>
    #include <string>
    #define LL long long
    
    using namespace std;
    
    LL m;
    map<LL, LL> s;
    
    LL dfs(LL n)
    {
        if (n == 1) return 0;
        if (n == 2) return 1;
        if (n == 3) return 2;
        if (n == 4) return 4;
        LL ans, t1 = 0, t2;
        if (n%4)
        {
            if (s[n/4+1] == 0)
            {
                t1 = dfs(n/4+1);
                s[n/4+1] = t1;
            }
            else t1 = s[n/4+1];
        }
        if (s[n/4] == 0)
        {
            t2 = dfs(n/4);
            s[n/4] = t2;
        }
        else t2 = s[n/4];
        ans = (n%4)*t1+(4-n%4)*t2;
        ans += n/4*4;
        if (n%4) ans += n%4-1;
        return ans;
    }
    
    int main()
    {
        //freopen("test.in", "r", stdin);
        int T;
        scanf("%d", &T);
        for (int times = 1; times <= T; ++times)
        {
            //s.clear();
            scanf("%I64d", &m);
            LL ans;
            ans = dfs(m+1);
            printf("%I64d
    ", ans);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    FreeCommander 学习手册
    String详解, String和CharSequence区别, StringBuilder和StringBuffer的区别 (String系列之1)
    StringBuffer 详解 (String系列之3)
    StringBuilder 详解 (String系列之2)
    java io系列26之 RandomAccessFile
    java io系列25之 PrintWriter (字符打印输出流)
    java io系列24之 BufferedWriter(字符缓冲输出流)
    java io系列23之 BufferedReader(字符缓冲输入流)
    java io系列22之 FileReader和FileWriter
    java io系列21之 InputStreamReader和OutputStreamWriter
  • 原文地址:https://www.cnblogs.com/andyqsmart/p/5003587.html
Copyright © 2020-2023  润新知